Tuesday, May 31, 2011

Singleton pattern and Volatile in java

Dear reader,
Here is the complete example with test cases of Singleton Pattern in java. 

Conditions of Singleton pattern:
1) One and only one instance of that Class.
2) Can't be cloned as cloning creates a new object violating Design principles of SingletonPattern.

3) Any sub-class of Singleton class should not be allowed as there is a default constructor in Sub-class 
   and using that multiple objects can be created. So Singleton class should have private default 
   constructor to avoid getting invoked using super() from sub-class constructor.
   
4) Make instance variable as Volatile. volatile ensures that multiple threads handle the object correctly 
   when it is being initialized in the SingletonPattern. For more details about "volatile", please see
   at the end of this article.
   
5) Also, it should be designed in such a way that even after De-Serialization too, same object should be 
   returned. As making serialization and de-serialization multiple instances can be created. I have given 
   an example for this too.
   

//Full example (SingletonPattern.java)
public class SingletonPattern {
    private volatile static SingletonPattern object=null;
    private SingletonPattern(){}   //No subclass can be created because of this private default constructor.

    public static SingletonPattern getInstance(){ //Never put synchronized in method, else other threads will be 
                                                  //blocked for getting object.
        if(object==null){                         //Check instance, if there isn't one, enter a synchronized block.
          synchronized (SingletonPattern.class) {  //We only synchronized the first time through.
               if(object==null){                   //Once in the block, double check for null and create an instance.   
                  object=new SingletonPattern();
             }
          }
        }
        return object;
    }
    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Cloning of this class is not allowed");  
    }
}

//Main test class (SingletonMain.java)
================Tries to extend SingletonClass: Prohibited================
/*public class SingletonMain extends SingletonPattern {
    public SingletonMain(){}   //Not allowed, as super class constructor is private.
    public static void main(String[] args) {
        SingletonPattern obj=SingletonPattern.getInstance();
        System.out.println(obj);

    }
}
*/
/*public class SingletonMain extends SingletonPattern { //Not allowed as it assumes a default constructor 
    //Constructor code is not written here.             //should be there in super class.
    public static void main(String[] args) {
        SingletonPattern obj=SingletonPattern.getInstance();
        System.out.println(obj);

    }
}
*/

================Tries to clone SingletonClass: Prohibited================
//Now your class need to implement Cloneable Interface and then only use the below
//code, else it will throw exception. Because if a class doesn't implement Cloneable,
//it can't be cloned.

public class SingletonMain implements Cloneable {                                
    public static void main(String[] args) throws Exception {
        SingletonPattern obj=SingletonPattern.getInstance();
        System.out.println(obj);
        SingletonPattern main=(SingletonPattern)(obj.clone()); //Will throw exception, cloning is prohibited.
        System.out.println(main);
    }
}

//Output when run SingletonMain class
SingletonPattern@360be0
Exception in thread "main" java.lang.CloneNotSupportedException: Cloning of this class is not allowed
    at SingletonPattern.clone(SingletonPattern.java:17)
    at SingletonMain.main(SingletonMain.java:25)
    

============================volatile===========================
Making instance volatile ensures that mulitple threads handle the object correctly when it is being 
initialized to the SingletonPattern class.

To Understand example of volatile keyword in java let’s go back to Singleton pattern in Java and see 
double checked locking in Singleton with Volatile and without volatile keyword in java.
------------------
//This example is representation of Singleton Pattern discussed above

public class SingletonPattern {
    private static volatile SingletonPattern _instance;
    public static SingletonPattern getInstance() {
        if(_instance == null){
            synchronized(SingletonPattern.class){
                if(_instance == null)
                    _instance = new SingletonPattern();
            }
        }
    return _instance;
    }
}
------------------
If you look at the code carefully you will be able to figure out:
1) We are only creating instance one time
2) We are creating instance lazily at the time of first request comes.

If we do not make _instance variable volatile then Thread which is creating _instance of SingletonPattern is 
not able to communicate other thread, that instance has been created until it comes out of the SingletonPattern 
block, so if Thread A is creating SingletonPattern instance and just after creation lost the CPU, all other 
threads will not be able to see value of "_instance" as not null and they will believe its still null.

Why because reader threads are not doing any locking and until writer thread comes out of synchronized 
block, memory will not be synchronized and value of _instance will not be updated in main memory. With 
Volatile keyword in Java this is handled by Java himself and such updates will be visible by all reader 
threads.


=======Last point to get the same object afer De-Serialization============
Now suppose we want the above Singleton class to be serializable. We can implement the Serializable interface 
for the above class and be done with it. But in that case we won’t be able to protect the singleton nature 
of the instance, such that after de-serialization there will be more than one instance of the class. 
This can be proved as follows:

Writing again the singleton pattern class:
////////////SingletonPattern.java
================================================
import java.io.ObjectStreamException;
import java.io.Serializable;
public class SingletonPattern implements Cloneable, Serializable{
    private volatile static SingletonPattern object=null;
    private SingletonPattern(){}   //No subclass can be created because of this private default constructor.

    public static SingletonPattern getInstance(){ //Never put synchronized in method, else other threads will be 
                                                  //blocked for getting object.
        if(object==null){                         //Check instance, if there isn't one, enter a synchronized block.
          synchronized (SingletonPattern.class) {  //We only synchronized the first time through.
               if(object==null){                   //Once in the block, double check for null and create an instance.   
                  object=new SingletonPattern();
             }
          }
        }
        return object;
    }
    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Cloning of this class is not allowed");  
    }    
}
================================================
//////Main class to fetch SingletonPattern Object and do Serialization:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class TestMain {
    public static void main(String[] args) throws Exception{
        SingletonPattern object=SingletonPattern.getInstance();
        System.out.println("Original Singleton Object: "+object);
        
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("out3.dat")));  
        out.writeObject(object);  
        out.close();  

        ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("out3.dat")));  
        SingletonPattern deserObject = (SingletonPattern) in.readObject();  

        //After de-serialization we will get different object
        System.out.println("Deserialized Singleton Object: "+deserObject);
        in.close();  
        
        //Returning false, should return true.
        System.out.println("This shows false, should be true: "+(object == deserObject));  
        
        //Returning true.
        System.out.println("This shows true: "+(object == SingletonPattern.getInstance()));  
    }
}
////Output:
Original Singleton Object: SingletonPattern@164eee
Deserialized Singleton Object: SingletonPattern@16a04a
This shows false, should be true: false
This shows true: true
================================================

You can analyze the output, two different Singleton Objects are there and equality shows FALSE.
This breaks the rule of Singleton class. The way to avoid this is using another hook, the readResolve() 
method. The readResolve() method is called when the  ObjectInputStream has read an object from the 
stream and is preparing to return it to the caller. ObjectInputStream checks whether the class of the 
object defines the readResolve() method. If the method is defined, the readResolve method is called to 
allow any changes in the object before it is returned.

So now we will add the readResolve() method in SingletonPattern.java, the modified code is:

================================
import java.io.ObjectStreamException;
import java.io.Serializable;
public class SingletonPattern implements Cloneable, Serializable{
    private volatile static SingletonPattern object=null;
    private SingletonPattern(){}   //No subclass can be created because of this private default constructor.

    public static SingletonPattern getInstance(){ //Never put synchronized in method, else other threads will be 
                                                  //blocked for getting object.
        if(object==null){                         //Check instance, if there isn't one, enter a synchronized block.
          synchronized (SingletonPattern.class) {  //We only synchronized the first time through.
               if(object==null){                   //Once in the block, double check for null and create an instance.   
                  object=new SingletonPattern();
             }
          }
        }
        return object;
    }
    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Cloning of this class is not allowed");  
    }
    private Object readResolve() throws ObjectStreamException {  
        return getInstance();  
    } 
}
================================

Now if you run the TestMain program again you will see output (it will show equality as TRUE) and
objects are equal. It means that even after de-serialization, we still have only one instance of the class in 
our JVM.
==============
//Output
Original Singleton Object: SingletonPattern@164efe
Deserialized Singleton Object: SingletonPattern@164efe
This shows false, should be true: true   
This shows true: true
==============

--------------------------------END-----------------------------------

4 comments:

  1. Hi Deepak. Can u elaborate more on Clone method described above. I dint under stand tht part.

    ReplyDelete
  2. Harinder,
    If you make your Singleton class implements Cloneable interface, then you have feasibility to override "clone()" method, there you can create a new object either using:

    SingletonPattern duplicateObject=new SingletonPattern();

    or

    SingletonPattern duplicateObject=(SingletonPattern)(existingObject.clone());

    However, Singleton pattern principle is: You have to create only one object of Singleton class per JVM.

    ReplyDelete
  3. Thanks deepak...gud work

    ReplyDelete
  4. Very well explained . Can we have a singleton in a cluster environment? If yes how ?

    ReplyDelete