jobs4timesLogo jobs4timesLogo

Singleton Design Pattern

If we create a class as singleton, an application allows only one instance of that class. Generally we create a class as singleton when we want global point of access to that instance.

  1. Declare the constructor of the class as private :
    Other classes in the application cannot create the object of the class directly(stops allowing more instances).

  2. Declare a static method :
    The methods of the same class can call the constructor to create objects, so in this method I can write the code to check and return only one object of the class.
    But if this method is a member method, to call it we need an object of the class(). So to call this method without the object, declare this object as static method.

  3. Declare a static member of the same class-type in the class :
    In the above static method, we need to write the code for returning only one instance of the class.

    How do you track whether an object for that class already exists ?
    When you will create a first object you will assign it to a member variable. So in the next call to the method, you just return the same object which you stored in the member variable.

    But member variables cannot be used in a static method, so you need to declare that variable as static variable to hold the reference of the same class.

The UML representation of the singleton :
singleton

Points to remember :
  • DateUtil() is a private constructor
  • instance is a static variable declared with in the class
  • getInstance() is a static method, acts as a factory method to create the object of the class.
package com.sinleton;

public class DateUtil {
	
 //declare static member of the same class-type in the class
 private static DateUtil instance;

 //constructor is declared as private
 private DateUtil(){ }
 
 //declare a static method to create only one instance
 //(static factory method)
 public static DateUtil getInstance(){
  if(instance==null){
	  instance=new DateUtil();
  }	 
 return instance;
 }//getInstance

}
we can write the above piece of code in various other ways and there are many ways to implement it.

1. Eager Initialization :

package com.sinleton;

public class DateUtil {
	
 //declare static member of the same class-type in the class
 
 private static DateUtil instance=new DateUtil();
 //instantiating the instance attribute when the class is loaded

 //constructor is declared as private
 private DateUtil(){ }
 
 //declare a static method to create only one instance
 //(static factory method)
 public static DateUtil getInstance(){
   return instance;
 }

}

2. Static block Initialization :

package com.sinleton;

public class DateUtil {
	
 //declare static member of the same as class-type
 private static DateUtil instance;
 
 
//static block execute once when the class is loaded
 static{
	instance=new DateUtil(); 
 } 
 

 //constructor is declared as private
 private DateUtil(){ }
 
 //declare a static method to create only one instance
 //(static factory method)
 public static DateUtil getInstance(){
   return instance;
 }

}
But the problem with above code is even you don't need the object also it will be instantiated.

3. Lazy Initialization :

  • In most of the cases it is recommended to delay the instantiation process until the object is needed.
  • To achieve this we can delay the creational process till the first call the getInstance() method.
  • But the problem with this is in a multi-threaded environment when more than one thread are executing at the same time, it might end-up in creating more than instances of the class.
  • To avoid this we can even declare that method as synchronized.
private static DateUtil instance;

public static synchronized DateUtil getInstance(){
 if(instance==null){
	 instance=new DateUtil();
 }
 return instance;
}
Instead of making the whole method as synchronized, it is enough to enclose only the condition check in synchronized block.
public static DateUtil getInstance(){
 synchronized(DateUtil.class){
 if(instance==null){
	 instance=new DateUtil();
 }
 }
 return instance;
}
  • Again we have a problem with the above piece of code, after the first call to the getInstance(), in the next calls to the method will check for instance==null check.
  • While doing this check, it acquires the lock to verify the condition which is not required.
  • Acquiring and releasing locks are quiet costly and we should avoid as much we can. To fix this we can have double level check for the condition as shown below.
public class DateUtil {
private static DateUtil instance;

private DateUtil(){ }
		
public static DateUtil getInstance(){
if(instance==null){
 synchronized(DateUtil.class){
	 //double check
 if(instance==null){
  instance=new DateUtil();
 }
}
}
return instance;
}
	
}
It is recommended to declare the static member instance as volatile to avoid problems in a multi-threaded environment.
public class DateUtil {
private static volatile DateUtil instance;

private DateUtil(){ }

public static DateUtil getInstance(){
if(instance==null){
 synchronized(DateUtil.class){
	 //double check
 if(instance==null){
  instance=new DateUtil();
 }
}
}
return instance;
}
	
}
It seems like with the above way we understand the best possible way of creating a singleton class.
Do you still see any drawbacks in the above piece of code ?
Yes, when we serialize and de-serialize a singleton class, the de-serialize process will creates as many number of objects for singleton class which avoids the rules of singleton.
import java.io.Serializable;

public class DateUtil implements Serializable{
private static DateUtil instance;

private DateUtil(){ }

public static DateUtil getInstance(){
if(instance==null){
 synchronized(DateUtil.class){
	 //double check
 if(instance==null){
  instance=new DateUtil();
 }
}
}
return instance;
}
	
}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SingletonTest{
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
	
DateUtil d1=DateUtil.getInstance();

ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(new File("e:\\dateUtil.ser")));
oos.writeObject(d1);

ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File("e:\\dateUtil.ser")));
DateUtil d2=(DateUtil)ois.readObject();
	
System.out.println("d1==d2 : ? "+(d1==d2));
 //the above statement returns false

}
}
So, how to avoid creating more than one objects of the singleton class even we serialize and de-serialize also.

That's where we need to write readResolve() method as part of singleton class.
The de-serialization process will call readResolve() on a class to read the byte stream to build the object.
If we write this method and can return the same instance of the class, we can avoid creating more than one object even in case of serialization as well.

package design;

import java.io.Serializable;

public class DateUtil implements Serializable{

 //declare static member of the same class-type in the class
 private static volatile DateUtil instance;

 //constructor is declared as private
 private DateUtil(){ }
	 
 //declare a static method to create only one instance (static factory method)
 public static DateUtil getInstance(){

 if(instance==null){
  synchronized (DateUtil.class) {
   if(instance==null){    //double-check
    instance=new DateUtil();
   }	 
  }
 }
 return instance;
 }//getInstance

protected Object readResolve(){
 return instance;
}

}
package design;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SingletonTest{
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
	
DateUtil d1=DateUtil.getInstance();

ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(new File("e:\\dateUtil.ser")));
oos.writeObject(d1);

ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File("e:\\dateUtil.ser")));
DateUtil d2=(DateUtil)ois.readObject();
	
System.out.println("d1==d2 : ? "+(d1==d2));
 //the above statement returns true

}
}
Override clone() method and throw CloneNotSupportedExcepton :
  • In order not to allow singleton class to be cloneable from created objects, it is even recommended to implement your class from Cloneable interface and override clone() method.
    Inside this method we should throw CloneNotSupportedException to avoid cloning of the object.

  • If you observe carefully clone() method is protected method in object class which cannot be visible outside the class unless we override.
  • The why do i need to implement from Cloneable and should throw exception in clone() method.

  • For e.g. if someone might write a class implementing Cloneable interface and calling super.clone() method in it.
  • If your singleton class extends from the other class, as the clone() method has been overridden in the base class you can use that method in cloning your object.

  • So to avoid such kind of instances, it is always said to be recommended to override the clone() method and throws exceptions.
package design;

import java.io.Serializable;

public class DateUtil implements Serializable,Cloneable{

 //declare static member of the same class-type in the class
 private static volatile DateUtil instance;

 //constructor is declared as private
 private DateUtil(){ }
	 
 //declare a static method to create only one instance (static factory method)
 public static DateUtil getInstance(){

 if(instance==null){
  synchronized (DateUtil.class) {
   if(instance==null){    //double-check
    instance=new DateUtil();
   }	 
  }
 }
 return instance;
 }//getInstance

protected Object readResolve(){
 return instance;
}

@Override
protected Object clone() throws CloneNotSupportedException{
	throw new CloneNotSupportedException();
	//super.clone();
	//return instance;
}

}
package design;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SingletonTest{
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException, CloneNotSupportedException {
	
DateUtil d1=DateUtil.getInstance();

ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(new File("e:\\dateUtil.ser")));
oos.writeObject(d1);

ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File("e:\\dateUtil.ser")));
DateUtil d2=(DateUtil)ois.readObject();
	
System.out.println("d1==d2 : ? "+(d1==d2));
 //the above statement returns true


DateUtil d3=(DateUtil) d1.clone();
System.out.println("d1==d3 : ? "+(d1==d3));
 //the above statement returns true
}
}


BACK