Saturday 29 May 2010

Singleton Design pattern

Singleton Design pattern:

Singleton design pattern is a java class, which allows us to create only one object per  JVM..


  • Sometimes it is important to have only one object for a class.
  • Generally Singletons are used for centralized management of internal or external resources and they provide a global point of access to themselves.
  • The singleton java class is used to encapsulate the creation of an object  in order to maintain control over it. This is nothing but a late instantiation (the instantiation of object can be delayed until it is actually needed. This is especially beneficial if the constructor needs to perform a costly operation, such as accessing a remote database.
Note:
  • When we want to create only one object or when the container is creating only one object even though that class allows to create multiple objects then that java class is not singleton java class.
  • According to this, then a java class of servlet program is not singleton java class. It is a normal java class for which Servlet container creates only one object
Where we have to use(Applications of Singleton):

  • It should be used when there must be exactly one object (instance) of a class, and when it must be accessible to clients from a global access point. (So provide a global point of access to the object)
  • if multiple applications of a project that are running from a single JVM wants to work with objects of java class having same data then it is recommended to make that java class as singleton java class. So that only one object will be allowed to create for that class and we can use that object for multiple tiles in multiple applications.
Example: 
  1. in Log4j (Logging for Java) environment tool, the Logger class is given as singleton java class
  2. java.lang.Runtime class is singleton java class
  3. java.awt.Desktop is singleton java class
Rules for Singleton Design Pattern:

  1. Declare a private static reference variable to hold current class Object. This reference variable will hold null only for the first time, after then it will refer to the object forever (till JVM terminates). We will initialize this reference using static factory method as discussed in step 3.
Example:
class Printer
{
   private static Printer p=null;
}
2.  Declare all the constructor as private so that its object can not be created from outside of the class using new keyword.

Example:
class Printer
{
 private static Printer p=null;
private Printer()
{
 System.out.println("Printer()");
}
}
3. Develop a static final factory method, which will return a new object only for the first time and the same object will be returned then after. Since we have only private constructor, we cannot use new keyword from outside of the program, we must declare this method as static, so that it can be accessed directly using Class Name. Declare this final so that the child class will have no option to override and change the default behaviour.

Ex:
 public static final Printer new Instance()
 {
    if(p==null)
    {
      p=new Printer();
    }
    return(p);
 }

4. Make Singleton class Reflection API proof /
we know that Reflection API can access the private variables, methods and constructors of the class, hence even if your constructor is private, we can still create the object of that class. To prevent this declare an instance boolean variable initiallialy holding true. Change its value to false, immediately when constructor is called for the first time. Then after when even the constructor is called for 2nd time, it should throw SomeException saying object can not be created for multiple times.
this approach also removes the Double checking problem in case of Multiple thread trying to create object at the same time.

Ex:
public class Printer
{
 private static boolean isNew=true;//1st time true, 2nd time is false, used for Reflection API proof, and multi-                                                    //Thread double check
 private Printer()
 {
   //to prevent Reflection API creating Multiple objects
   isNew=false;
   System.out.println("Printer()");
 }
  else
 {
   throw new InstanceiationError("Can not create Multiple objects");
  }
 }
}

5. Make Factory Method Thread safety, so that Only one object is created even if more than one thread tries to call this method simultaneously. Declare the whole method as synchronized method, or use synchronized block.
public synchronized final static Printer getInstance()
{
 if(p==null)
  p=new Printer();
 return(p);
}
 (or)
public static final Printer getInstance()
 {
   if(p==null) //1st null check
   {
     synchronized(Printer.class)
     {
       if(p==null)//2nd null check
       {
         p=new Printer();
       }
     }
  }
  return(p);
}
Note: In case of synchronized block we have done null check for 2 times. Lets find out why:

Assume 2 threads are calling getInstance() simultaneously and there is no 2nd Null check. Thread1 calls getInstance() first, finds p=null for the 1st time, then gets lock on Printer class. Once it gets the lock it enter synchronized block and starts creating printer class object by calling the constructor for the 1st time. Assume the object creation will take 10 seconds, due to lots of background activities. At the same time Thread2 calls getInstance(). It also finds p=null (As object is not created ye) enters the first Null check. It will then try to acquire lock on Pritner class, But since its alrady been acquired by Thread1, Thread2 has to wait for 10 sec outside of synchronized block. After 10 second Thread1 will complete the object creation process and then releases the lock. Once lock is released Thread2 will acquire the lock and enters inside the Synchronized block. Now if we don't have 2nd null check, the Object will be created for 2nd times as well, which is what we don't want. Hence we have two level have used the two of null checks here.

Note: If you have used the Reflection PRoof logic, then no need to worry about the 2nd null check. Because when you call the constructor for 2nd time, it will throw InstantiationError.

6. Prevent Singleton object from De-serialization. If you need singleton object to send across the network, singleton class must implement serialization interface. But problem with this approach is we can de-serialize it for N number of times, and each deseriliazation process will create a brand new object , which will violate the singleton Design pattern.

In order to prevent multiple object creation during deserialization process, override readResolve() and return the same object. readResolve method is called internally in the process of deserialization. It is used to replace de-serialized ojbect by choice.

public class Printer
{
 private static Printer p=null;
 private Printer()
{
..
 }
 //any deserialization process will give the same object
  protected Object readResolve()
  {
    System.out.println("readResolve()");
  return(p);
 }
}
Note: ignore this process if class does not implement serializable interface directly or indirectly. Indirectly means the super class or super interfaces has not implmented/extended Serializable interface.

7. Prevent Singleton Object being Cloning. If your class is direct child of Object class, then I will suggest not to implement Cloneable Interface, as there is no meaning of cloning the singleton object to produce duplicate objects out of it. Both are opposite to each other. However if class is the child of some other class or interface and that class or interface has implemented/extended Cloneable interface, then it is possible that somebody may clone your singleton class thereby creating many objects. We should prevent this as well .

Override clone() in your singleton class and return the same old object. You may also throw CloneNotSupportedException.

public class Printer
{
 private static Printer p=null;
 private Printer()
 {
   ...
  }
//any cloning process will return you the same old object
 public Object clone() throws CloneNotSupportedException
 {
   //throw new CloneNotSupportedException();
   return(p);//If you want to return the same old object
 }
}

8. Inspite of all the above efforts, There is still a loop hole "The boss Reflection API ". Using refection API, the programmer can get access to private constructors, variables, and methods, We have to prevent this for Singleton Design Pattern.

Declare a static instance variable to count how many times the object. For the first time when ever constructor is called, increment the count to 1. Next time when constructor is called, check if the value is one or not. If yes, throw InstantiationError.
The below code makes singleton java class as Thread safety without using Reflection API proof code and synchronization concepts.
9. Use Static block or static defination. If you feel you don't want to use synchronized method or block but still want to achieve singleton behavior. you can use static block or static definition to initialize the singleton java class object as follows.

public class Printer
{
private static Printer p=new Printer();
 /* or
 private static Printer p=null;
 static
 {
   p=new Printer();
  }
*/
 
//private constructor
private Printer()
{
System.out.println("Printer()");
}
public void print(String data)
{
System.out.println("Printer.print()..printing:"+data);
}
public final static Printer getInstance()
{
return(p);
}//end of getInstance()
Note: This approach will create the Object even if you don't need them urgently (during class loading). This is not used so frequently in the industry.

No comments:

Post a Comment