Saturday, October 29, 2016

How to create a Singleton class

Q)What is a singleton class?

A)In simple words,  A singleton class is a class which can have only one instance at any point of time throughout the application and provides a global point of access to its instance.

Q)Ok, How can you create a singleton class?

A)
class Singleton {
       public static final Singleton INSTANCE = new Singleton();

       private Singleton() {
       }
}

                 This is a simple example for a singleton class where I used a public static final INSTANCE variable and
initialized it with a Singleton object. Since INSTANCE is public static final, it can’t be reassigned and it is thread safe as well. 
                 Singleton’s constructor is made private to prevent the instantiation of Singleton class from other classes. That means no other class can create an object for Singleton class with the new() operator and also no other class can extend this Singleton class with extends keyword. If any class wants to have an instance of Singleton it can have by accessing INSTANCE field of Singleton class like Singelton.INSTANCE as its static.

Q) So here, Singleton instance will be created at the time of class loading that means when the Singleton class is loaded by JVM into memory. So it’s an early loading/instantiation of Singleton class and it occupies memory even when its not required yet, so what If we want this singleton instance to be created when it’s really required?

A) I understand that you are interested in lazy loading/instantiation of Singleton. Here it is

class Singleton {
       private static Singleton INSTANCE;

       private Singleton() {
       }

       public static synchronized Singleton getInstance() {
              if (INSTANCE == null) {
                     INSTANCE = new Singleton();
              }
              return INSTANCE;
       }
}

Q) You synchronized the whole method
       public static synchronized Singleton getInstance()

Don’t you see any performance overhead with this approach? 
Only one thread can access the method getInstance at a time to get the Singleton instance and rest of all other threads need to wait even though INSTANCE is not null as its already created.

A)Hmm..Yeah. Let me create it using synchronized block instead of synchronized method, here how it goes

class Singleton {
       private static Singleton INSTANCE;

       private Singleton() {
       }

       public static Singleton getInstance() {
              if (INSTANCE == null) {             //----- 1st
                     synchronized (Singleton.class) {
                           if (INSTANCE == null) {   //----- 2nd
                                  INSTANCE = new Singleton();
                           }
                     }
              }
              return INSTANCE;
       }
}

Q) Ok, but why do you use null check twice here?

A) I think I don’t need to explain you why did I use first null check, as you know I am going to create Singleton instance in case INSTANCE is null otherwise I ll return the already created instance.
2nd null check is being used to ensure thread safety. 

For suppose, 2 threads are concurrently trying to get the access for getInstance() and two threads are gone through the 1st null check and trying to enter into synchronized block, but only one thread(assume thread-1) got the lock on Singleton.class’s  object and enters the synchronized block while the other thread (assume thread-2)waiting for the lock. Once thread-1 went through 2nd null check then it creates a Singleton instance as INSTANCE is null and leaves the synchronized block and thus releases lock. Now, the waiting thread ( thread-2) holds the lock and enters the synchronized block.

If there is no 2nd null check there then there is a chance for the thread-2 to create another instance of Singleton class and thus it breaks the singleton here. For that reason we have 2nd null check here. So the thread-2 sees that INSTANCE is not null and comes out from the synchronized block without creating Singleton instance.

Q) Ok. So double checking is for thread safety of a singleton.


A) yes

Q)Do you think that, this Singleton class is still singleton?

I can break your singleton with the help of reflection like below

public class Test {
       public static void main(String args[]) {
              Singleton singleton1 = Singleton.getInstance();
              Singleton singleton2 = null;
              try {
                     // Test is package name contains Singleton class
                     Class singletonClass = Class.forName("Test.Singleton"); 
                     // as we know there is only one private constructor
                     Constructor cons = singletonClass.getDeclaredConstructor();
                     cons.setAccessible(true); 
                     singleton2 = (Singleton) cons.newInstance();
                     System.out.println(singleton1 == singleton2 ? "Objects are equal" : "Objects are different");
              } catch (ClassNotFoundException | InstantiationException
                           | IllegalAccessException | IllegalArgumentException
                           | InvocationTargetException | NoSuchMethodException
                            | SecurityException e) {
                     e.printStackTrace();
              }
       }
}

A) In that case I can implement Singleton like below for not to be broken with reflection

class Singleton {
       private static Singleton INSTANCE;

       private Singleton() {
              if (INSTANCE != null)
                     throw new RuntimeException(
                                  "Singleton can not be created more than once.");
       }

       public static Singleton getInstance() {
              if (INSTANCE == null) {
                     synchronized (Singleton.class) {
                           if (INSTANCE == null) {
                                  INSTANCE = new Singleton();
                           }
                     }
              }
              return INSTANCE;
       }
}

Private constructor will be called to instantiate the Singleton object through reflection. So we can throw some exception If INSTANCE field is not null (that means its already created).

Q) Hmm, So you think this implementation saves your Singleton from being broken from reflection. In my previous program, I am trying to create a Singleton object (singleton1) with the help of getInstance() and after that trying to create another object (singleton2) with the help of reflection. What happens If I do this in reverse like below

public class Test {
       public static void main(String args[]) {
//            Singleton singleton1 = Singleton.getInstance();
              Singleton singleton2 = null;
              try {
                     // Test is package name contains Singleton class
                     Class singletonClass = Class.forName("Test.Singleton"); 
                     // as we know there is only one private constructor
                     Constructor cons = singletonClass.getDeclaredConstructor();
                     cons.setAccessible(true); 
                     singleton2 = (Singleton) cons.newInstance();
                     Singleton singleton1 = Singleton.getInstance();
                     System.out.println(singleton1 == singleton2 ? "Objects are equal" : "Objects are different");
              } catch (ClassNotFoundException | InstantiationException
                            | IllegalAccessException | IllegalArgumentException
                           | InvocationTargetException | NoSuchMethodException
                           | SecurityException e) {
                     e.printStackTrace();
              }
       }
}

Output:
 Objects are different

Here, If I try to create a Singleton object (singleton2) with the help of reflection first then it can proceed to create an Singleton object as the static field INSTANCE is still null at that time as getInstance() is not yet invoked. So we are allowed to create an many as objects we want for the Singleton using reflection before getInstance() is invoked and thus breaks the singleton. What do you say?

A) Yeah, you are right. Let me come to you with slightly modified implementation of Singleton which protects itself from being broken with reflection.

class Singleton {
       private static Singleton INSTANCE;
       private static boolean instanceCreated = false;

       private Singleton() {
              if (INSTANCE != null || instanceCreated)
                     throw new RuntimeException(
                                  "Singleton can not be created more than once.");
              instanceCreated = true;

              INSTANCE = this;
       }

       public static Singleton getInstance() {
              if (INSTANCE == null) {
                     synchronized (Singleton.class) {
                           if (INSTANCE == null) {
                                  INSTANCE = new Singleton();
                           }
                     }
              }
              return INSTANCE;
       }
}

Here I created a Boolean static variable “InstanceCreated”  and initialized it with default value “false” and set it to “true” in the constructor when the instance is created through the constructor for the first time. I also initialize the INSTANCE field with the “this” object in the constructor to hold the reference of Singleton when its first created through the reflection.

Q)Ok.  Seems good, but I can also break your singleton using serialization like below by assuming  your class or your class’s parent class implements Serializable interface

public class Test {
       public static void main(String args[]) {
              Singleton singleton1 = Singleton.getInstance();
              Singleton singleton2 = null;
              ObjectOutputStream out = null;
              ObjectInputStream in = null;
              try {
                     out = new ObjectOutputStream(new FileOutputStream("serialize.file"));
                     out.writeObject(singleton1);
                     in = new ObjectInputStream(new FileInputStream("serialize.file"));
                     singleton2 = (Singleton) in.readObject();
                     System.out.println(singleton1 == singleton2 ? "Objects are equal"
                                  : "Objects are different");
              } catch (IOException | ClassNotFoundException e) {
                     e.printStackTrace();
              } finally {
                     try {
                           out.close();
                           in.close();
                     } catch (IOException e) {
                           e.printStackTrace();
                     }
              }
       }
}

A)  To protect my Singleton from being broken with serialization, I can implement this way

class Singleton implements Serializable {
       private static final long serialVersionUID = 1L;
       private static Singleton INSTANCE;

       private static boolean instanceCreated = false;

       private Singleton() {
              if (INSTANCE != null || instanceCreated)
                     throw new RuntimeException(
                                  "Singleton can not be created more than once.");
              instanceCreated = true;
       }

       public static Singleton getInstance() {
              if (INSTANCE == null) {
                     synchronized (Singleton.class) {
                           if (INSTANCE == null) {
                                  INSTANCE = new Singleton();
                           }
                     }
              }
              return INSTANCE;
       }

       private Object readResolve() {
              return INSTANCE;
       }
}

Just look at readResolve() method which has been defined in Singleton class.
       private Object readResolve()

readResolve() method is called just after the readObject() method and just before returning the prepared object from ObjectInputStream to the caller while deserialization. So here we defined readResolve()  and returning the same INSTANCE variable which thus being returned as a result of serialization instead of new serialized object.

Q)Ohh Ok, I can still break your singleton by cloning (assuming  your Singleton extends another class which implements Cloneable)

class A implements Cloneable {
       @Override
       public Object clone() throws CloneNotSupportedException {
              return super.clone();
       }
}

Assume your Singleton class extends the class A and I can create another Singleton instance with the help of clone() like below

public class Test {
       public static void main(String args[]) {
              Singleton singleton1 = Singleton.getInstance();
              Singleton singleton2 = null;
              try {
                     singleton2 = (Singleton) singleton1.clone();
                     System.out.println(singleton1 == singleton2 ? "Objects are equal"
                                  : "Objects are different");
              } catch (CloneNotSupportedException e) {
                     e.printStackTrace();
              }
       }
}

A) Ok, in that case I can protect my Singleton by overriding clone() method and throws 
“CloneNotSupportedException” like below

class Singleton extends A implements Serializable {
       private static final long serialVersionUID = 1L;
       private static Singleton INSTANCE;

       private static boolean instanceCreated = false;

       private Singleton() {
              if (INSTANCE != null || instanceCreated)
                     throw new RuntimeException(
                                  "Singleton can not be created more than once.");
              instanceCreated = true;
       }


       public static Singleton getInstance() {
              if (INSTANCE == null) {
                     synchronized (Singleton.class) {
                           if (INSTANCE == null) {
                                  INSTANCE = new Singleton();
                           }
                     }
              }
              return INSTANCE;
       }
      
       private Object readResolve() {
              return new Object();
       }
      
       @Override
       public Object clone() throws CloneNotSupportedException {
              throw new CloneNotSupportedException();
       }
}

Q)Hmm, Ok. Good. Lets meet again.
A) Sure.

2 comments:

  1. Nice article on Singleton pattern Ganesh, really well compiled...

    ReplyDelete
  2. Asking qestіons are truly pleasant thing if you are not understandiing anything totallʏ, except this pοst
    presents fastidious understandіng even.

    ReplyDelete