Singleton Pattern

Singleton Pattern

This post is from geeksforgeeks:

Classic Implementation

class Singleton {

    private static Singleton obj;

    private Singleton() {}

    public static Singleton getInstance()
    {
        if (obj==null)
            obj = new Singleton();

        return obj;
    }
}

The main problem with above method is that it is not thread safe.

make getInstance() synchronized

class Singleton {

    private static Singleton obj;

    private Singleton() {}

    // Only one thread can execute this at a time
    public static synchronized Singleton getInstance() {

        if (obj==null)
            obj = new Singleton();

        return obj;
    }
}

The main disadvantage of this is method is that using synchronized every time while creating the singleton object is expensive and may decrease the performance of your program.

However if performance of getInstance() is not critical for your application this method provides a clean and simple solution.

Eager Instantiation

class Singleton {

    private static Singleton obj = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return obj;
    }
}

JVM executes static initializer when the class is loaded and hence this is guaranteed to be thread safe. Use this method only when your singleton class is light and is used throughout the execution of your program.

Double Checked Locking

class Singleton {

    private volatile static Singleton obj;

    private Singleton() {}

    public static Singleton getInstance() {

        if (obj == null) {
            // To make thread safe
            synchronized (Singleton.class)
            {
                // check again as multiple threads
                // can reach above step
                if (obj==null)
                    obj = new Singleton();
            }
        }

        return obj;
    }
}

We have declared the obj volatile which ensures that multiple threads offer the obj variable correctly when it is being initialized to Singleton instance. This method drastically reduces the overhead of calling the synchronized method every time.

Cases that break Singleton

Reflection

public class Singleton {

    public static Singleton instance = new Singleton();

    private Singleton()  {

    }
}

public class GFG {

    public static void main(String[] args) {

        Singleton instance1 = Singleton.instance;
        Singleton instance2 = null;
        try {
            Constructor[] constructors =
                    Singleton.class.getDeclaredConstructors();
            for (Constructor constructor : constructors) {
                // Below code will destroy the singleton pattern
                constructor.setAccessible(true);
                instance2 = (Singleton) constructor.newInstance();
                break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    System.out.println("instance1.hashCode():- "
                                      + instance1.hashCode());
    System.out.println("instance2.hashCode():- "
                                      + instance2.hashCode());
    }
}

After running this class, you will see that hashCodes are different that means, 2 objects of same class are created and singleton pattern has been destroyed.

Solution

Use Enum to overcome reflection issue.

Serialization

Serialization is used to convert an object of byte stream and save in a file or send over a network.

Suppose you serialize an object of a singleton class. Then if you de-serialize that object it will create a new instance and hence break the singleton pattern.

class Singleton implements Serializable
{
    // public instance initialized when loading the class
    public static Singleton instance = new Singleton();

    private Singleton()
    {
        // private constructor
    }
}


public class GFG
{

    public static void main(String[] args)
    {
        try
        {
            Singleton instance1 = Singleton.instance;
            ObjectOutput out
                = new ObjectOutputStream(new FileOutputStream("file.text"));
            out.writeObject(instance1);
            out.close();

            // deserailize from file to object
            ObjectInput in
                = new ObjectInputStream(new FileInputStream("file.text"));

            Singleton instance2 = (Singleton) in.readObject();
            in.close();

            System.out.println("instance1 hashCode:- "
                                                 + instance1.hashCode());
            System.out.println("instance2 hashCode:- "
                                                 + instance2.hashCode());
        } catch (Exception e)  {
            e.printStackTrace();
        }
    }
}
Solution

To overcome this issue, we have to implement method readResolve() method.

class Singleton implements Serializable
{
    public static Singleton instance = new Singleton();

    private Singleton()
    {

    }

    protected Object readResolve()
    {
        return instance;
    }
}

Cloning

Suppose, we ceate clone of a singleton object, then it wil create a copy that is there are two instances of a singleton class, hence the class is no more singleton.

Solution

Override the clone method.

Written on October 15, 2018