Singleton Design Pattern

We need to create a class which can have only one instance at any time.

Solution 1:


      public class MySingleton {  
           private static MySingleton singleton= new MySingleton();  
           private MySingleton(){ System.out.println( "Object Created" ); }  
           public static MySingleton getMySingleton(){  
                return singleton;  
           }  
      }  


Let's create the object when we need it, not at the time of loading the class.

Solution 2(with Lazy loading):


      public class MySingleton {             // Line : 1  
           private static MySingleton singleton=null;          // Line : 2  
           private MySingleton(){ System.out.println( "Object Created" ); } // Line : 3  
           public static MySingleton getMySingleton(){          // Line : 4  
                if(singleton == null)                              // Line : 5  
                {  
                     singleton = new MySingleton();               // Line : 6  
                }  
                return singleton;                                   // Line : 7  
           }  
      }  




When multiple threads reach "Line : 5" at the same time, multiple objects can be created.

Solution 3: Using synchronized method



      public class MySingleton {  
           private static MySingleton singleton=null;  
           private MySingleton(){ System.out.println( "Object Created" ); }  
           public static synchronized MySingleton getMySingleton(){  
                if(singleton == null)  
                {  
                     singleton = new MySingleton();  
                }  
                return singleton;  
           }  
      }  



Even to check the 'not null' condition, all threads need to wait, to acquire lock on that class. As the method is synchronized, we are paying the cost of synchronization for every thread invocation of the method, even though it is only required on the first thread invocation.
synchronize only the instance creation not the whole method.

Solution 4: Using synchronized block



      public class MySingleton {                                                       // Line : 1  
           private static MySingleton singleton=null;                              // Line : 2  
           private MySingleton(){ System.out.println( "Object Created" ); }     // Line : 3  
           public static MySingleton getMySingleton(){                              // Line : 4  
                if(singleton == null)                                                  // Line : 5  
                {  
                     synchronized (MySingleton.class) {                              // Line : 6  
                          singleton = new MySingleton();                              // Line : 7  
                     }  
                }  
                return singleton;                                                       // Line : 8  
           }  
      }  


There is a problem in the above solution. Let's say there are two threads A and B. Thread A and thread B executes "Line: 5" at the same time. As the singleton object is yet to be instantiated, both satisfies the null check and enters into "Line: 6". As we are using synchronized block here, only one thread i.e. first thread (say Thread A) gets the lock on class and creates the singleton object, Thread B wait outside at "Line:6" until Thread A releases the lock. Once it releases the lock, Thread B also gets the lock and creates one more object. It can be resolved by checking null one more time inside the synchronized block.

Solution 5: Using Double-checked locking



 public class MySingleton {  
           private static MySingleton singleton=null;  
           private MySingleton(){ System.out.println( "Object Created" ); }  
           public static MySingleton getMySingleton(){  
                if(singleton == null)  
                {  
                     synchronized (MySingleton.class) {  
                          if(singleton == null)  
                          {  
                               singleton = new MySingleton();  
                          }  
                     }  
                }  
                return singleton;  
           }  
      }  


It looks like, it is a perfect solution. No,it is not. 

Note : Our Java compiler is free to reorder the instructions.

Let's say there are two threads A and B.Imagine that thread A is inside the synchronized block, executing the statement singleton = new MySingleton(); while thread B is just entering getMySingleton(). Consider the effect on memory of this initialization. Memory for the new MySingleton object will be allocated; the constructor for MySingleton will be called, initializing the member fields of the new object; and the field singleton of MySingleton will be assigned a reference to the newly created object.

However, since thread B is not executing inside a synchronized block, it may see these memory operations in a different order than the one thread A executes. It could be the case that B sees these events in the following order (and the compiler is also free to reorder the instructions like this): allocate memory, assign reference to singleton, call constructor. Suppose thread B comes along after the memory has been allocated and the singleton field is set, but before the constructor is called. It sees that singleton is not null, skips the synchronized block, and returns a reference to a partially constructed singleton! Needless to say, the result is neither expected nor desired. 

Reference:: From JavaWorld

Solution 6: Using Volatile

volatile ensures that the system will not allow a write of a volatile to be reordered with respect to any previous read or write, and a read of a volatile cannot be reordered with respect to any following read or write



 public class MySingleton {  
           private static volatile MySingleton singleton=null;  
           private MySingleton(){ System.out.println( "Object Created" ); }  
           public static MySingleton getMySingleton(){  
                if(singleton == null)  
                {  
                     synchronized (MySingleton.class) {  
                          if(singleton == null)  
                          {  
                               singleton = new MySingleton();  
                          }  
                     }  
                }  
                return singleton;  
           }  
      }  


Usually you sould not implement eaither Serializable or Cloneable while wrinting a singleton class. 
Even if your singleton class implments Cloneable, here is how you can still make sure that there will be only one object for your single tom class.
Just override the clone method to throw an exception like below.

Solution 7: can't be cloned.


      public class MySingleton implements Cloneable {  
           private static volatile MySingleton singleton=null;  
           private MySingleton(){ System.out.println( "Object Created" ); }  
           public static MySingleton getMySingleton(){  
                if(singleton == null)  
                {  
                     synchronized (MySingleton.class) {  
                          if(singleton == null)  
                          {  
                               singleton = new MySingleton();  
                          }  
                     }  
                }  
                return singleton;  
           }  
           @Override  
        protected Object clone() throws CloneNotSupportedException {  
          throw new CloneNotSupportedException("Cloning of this class is not allowed");   
        }  
      }  


Sometimes in distributed systems, we need to implement Serializable interface in Singleton class so that we can store it’s state in file system and retrieve it at later point of time. Here is a small singleton class that implements Serializable interface also.

To make a singleton class serializable, it is not sufficient merely to add implements Serializable to its declaration. To maintain the singleton guarantee, you have to declare all instance fields transient and provide a readResolve method. Otherwise, each time a serialized instance is deserialized, a new instance will be created
readResolve works only when all fields are transient.

Solution 8: using readResolve().


 import java.io.ObjectStreamException;  
      import java.io.Serializable;  
      public class MySingleton implements Cloneable,Serializable {  
           private static volatile MySingleton singleton=null;  
           private MySingleton(){ System.out.println( "Object Created" ); }  
           public static MySingleton getMySingleton(){  
                if(singleton == null)  
                {  
                     synchronized (MySingleton.class) {  
                          if(singleton == null)  
                          {  
                               singleton = new MySingleton();  
                          }  
                     }  
                }  
                return singleton;  
           }  
           @Override  
        protected Object clone() throws CloneNotSupportedException {  
          throw new CloneNotSupportedException("Cloning of this class is not allowed");   
        }  
           protected Object readResolve() throws ObjectStreamException {  
             return singleton;  
           }  
      }  


After all here is the new simple singleton which can handle lazy inititialization, serialization and they are thread safe. Newly introduced in JAVA 1.5.


Solution 9: using ENUM.


 public class MySingleton {  
            private static enum SingletonEnum {   
               INSTANCE;  
               private static final MySingleton singleton = new MySingleton();  
               public MySingleton getSingleton() {  
                 return singleton;  
               }  
             }  
           private MySingleton(){ System.out.println( "Object Created" ); }  
           public static MySingleton getMySingleton(){  
                return SingletonEnum.INSTANCE.getSingleton();  
           }  
      }  






Comments

  1. Review Comments:

    In example 8, you have removed volatile, the variable should be declared as.

    public static transient volatile MySingleton singleton = null

    Please revise.

    ReplyDelete
    Replies
    1. Thanks M.V.K for pointing out my mistake. There is one more mistake in the same line.
      We don't need to define a variable as transient along with static. Static fields are always transient. I will be updating both.

      Delete

Post a Comment

Popular posts from this blog

What's New in JAVA 8

Internals of JSF