Singleton Pattern in Java Tutorial . Use Enum type to implement Singleton example code .

Do you need to limit the maximum number of instances of a class to exactly one for your application? Use Singleton pattern . One of the design patterns in software engineering is creational patterns which prescribe the way that objects are created . One of the useful creational design patterns is Singleton pattern which ensures that there is only one instance of a class, and that there is a global access point to that object. A class that implements the Singleton pattern is called a Singleton class.
The design of Singleton class should ensure the following
1. the class is instantiated only once and further requests to the class to create instance are forced to return a reference to the existing one and only object.
2. the instantiation of the class can be delayed until it is actually needed ( lazy instantiation) . lazy instantiation is beneficial in many situations because it requires no memory or resources until it is required For example , connecting a remote database when the application starts which is very costly operation.
3. the class itself is completetly responsible for ensuring the above constraints, not the clients of the class.

Examples : A good example of a singleton is a logging service. The logging service is a single event for all listeners and needs only one instance. Many applications use Sigleton pattern to restrict the maximum number of connections to one for database connections or sockets . And many system components such as file system , windows task manager , etc. use the singleton pattern . Some of the applications are restricted to open only one instance of it . for eg. db2 control center (db2cc) multiple requests to db2cc shares the the same instance which is already running. One practical life example is , Find and Replace dialog box in Microsoft Word . There can be only one Find and Replace dialog box for a single and multiple documents .When you press Ctrl-H two or more times, there is only one Find & Replace dialog box .

Now how to ensure that there is only one instance of a class? A Simple implementation will be done by doing the following
1. Make the constructor private which is not accessible from outside of the class . (i.e. client of the class should not be able to invoke the class's constructor using new keyword)
2. Add a static field to have a single instance of the class.
3. Add a public static method to allow clients access that is solely responsible for creating the single instance of the class by calling the constructor and return this instance to the caller of the static method

The following versions of singleton are implemented below
1. Singleton which supports Lazy instantiation
2. Multithreaded Singleton
3. Singleton which supports Lazy instantiation & thread safe
4. Double-checked locking
5. Singleton with Enum type

This following code demonstrates how the Singleton pattern can be used to to provide unique sequential numbers similar to primary keys in a database
Singleton 1 :
    
 class PrimaryKeyGenerator{ 
   private static  PrimaryKeyGenerator instance;
   private static int key;
   private PrimaryKeyGenerator() {key=0;}

   public static PrimaryKeyGenerator getInstance()
   {
        if (instance == null)
       {
            instance = new PrimaryKeyGenerator();
        }
         return instance;
      }

  public  int getNext()
   {
    return ++key;
   }
 }

Calling getNext() : PrimaryKeyGenerator.getInstance().getNext();

The above code supports lazy instantiation but not safe for multithreaded environments. If two threads enter the getInstance() method at the same time, each thread could execute the statement if (instance == null) before executing the statment instance = new PrimaryKeyGenerator(); . Now both thread determines that a new instance has to be created:

The following Static initialization code implementation is safe for multithreaded environments but not supports lazy instantiation . When the class is initialized , singleton object is created.
Singleton 2 :
    
class PrimaryKeyGenerator { 
private static int key;
 private static final PrimaryKeyGenerator  instance =   new PrimaryKeyGenerator(); 
 private PrimaryKeyGenerator() {  key=0;  } 
 public static PrimaryKeyGenerator getInstance() { 
     return instance;  
 } 
..............
................
}

In the above strategy, single instance is created when static field is assigned .Only one PrimaryKeyGenerator instance will be created , once the PrimaryKeyGenerator class is initialized. JVM takes care of the staticvariable initialization . Static initialization is suitable for most of the situations . The above code is wriiten with a public static factory method .
Without using public static factory method , the above code can be written as follows
Singleton 3 :
    
class PrimaryKeyGenerator { 
private static int key;
private static final PrimaryKeyGenerator  instance =   new PrimaryKeyGenerator(); 
private PrimaryKeyGenerator() {  key=0;  } 
..............
..............
}

Calling getNext() : PrimaryKeyGenerator.instance.getNext();

The following code is for implementing the singleton class thread safe with the support of lazy instantiation . One way to do is to protect the getInstance() method of Singleton 1 through synchronization.
Singleton 4 :
    
...............
.............
   public static synchronized PrimaryKeyGenerator getInstance()
   {
       if (instance == null)
       {
            instance = new PrimaryKeyGenerator();
        }
         return instance;
      }
.................
.................

The above code works fine when two or more thread access to the getInstance() method . But it performs synchronization every invocation of getInstance() . Actually synchronization is required on the first invocation only . After that singleton object is created. During the first invocation of getInstance() method , only line to be executed is instance = new PrimaryKeyGenerator(); to create the instance. Once the object is created , this line will not be executed again. So that is the only line that requires synchronization. So the above code (Singleton 3 ) can be changed as below.
Singleton 5 :
    
...............
.............
   public static PrimaryKeyGenerator getInstance()
   {
          if (instance == null)
       {
         synchronized(PrimaryKeyGenerator.class) 
 {
            instance = new PrimaryKeyGenerator();
 }
        }
         return instance;
      }
.................
.................

But the above code again becomes not safe for multithreaded environments as in the case Singleton 1 . The following code fixes the above problem by putting the second check of instance inside the synchronized statement . This is called Double-checked locking
Singleton 6 :
    
...............
..............
 public static  PrimaryKeyGenerator getInstance()
   {
            if (instance == null)
       {
        synchronized(PrimaryKeyGenerator.class)
         {
           if (instance == null)   
             {  
             instance = new PrimaryKeyGenerator(); 
               }
           }
        }
         return instance;
      }
................
................

The above code is suitable for multithreaded environments. The problem with double-checked locking is that the code does not work in the presence of either optimizing compilers or shared memory multiprocessors. More on that can be viewed at Failure of Double-Checked Locking

Some of the tricky interview questions may be asked about Singleton class
1. Private constructor can be accessed using java reflection .Then how to avoid creation of second instance of Singleton class when using reflection? Ans : throw an exception inside constructor when it is called to create a second instance. More on accessing private constructor using reflection can be viewed at my earler post reflection to access private constructor to create object

2. How to prevent the creation of a new instance during each deserialization of a serialized instance of Singleton class? Ans : declare all instance fields transient and add a readResolve() method
private Object readResolve() throws ObjectStreamException {
return instance;
}

Now the final implementation of Singletons can be done using Enum type with one element may be the best approach (Reference : from "Effective Java" book second edition by Joshua Bloch ) . The code is as follows works with JDK 1.5 and above
Singleton 7 :
    
enum  PrimaryKeyGenerator1{ 
 instance;
private static int key;
public   int getNext()
{
return ++key;
}
}

Calling getNext() : PrimaryKeyGenerator1.instance.getNext();

The above code uses enum type with one element to implement singleton and it is very easy to implement ; safe for multithreaded environments and not to worry about multiple instantiation using deserialization of serialized instance and reflection . To test all above versions of the Singleton class with Multiple Threads , use the following code .
    
public class SingletonTest1
{
public static void main(String args[])
{
    for (int i = 0; i < 10; i++) {
      Thread p1 = new Thread(new ThreadOne());
      Thread p2 = new Thread(new ThreadTwo());
      p2.start();
      p1.start();
      Thread p3 = new Thread(new ThreadOne());
      Thread p4 = new Thread(new ThreadTwo());
      p3.start();
      p4.start();
    }
}
}

class ThreadOne implements Runnable {
public void run() {
System.out.print(PrimaryKeyGenerator.getInstance().getNext()+"  ");  
//System.out.print(PrimaryKeyGenerator.instance.getNext()+"  ");    // For Singleton 3 and Singleton 7
}
}
class ThreadTwo implements Runnable {
public void run() {
System.out.print(PrimaryKeyGenerator.getInstance().getNext()+"  ");
}
}

PrimaryKeyGenerator class of Singleton 1 & 5 are instantiated more than once when using multi threads

5 comments:

kobrys said...

Do not use Singleton!

If you use enum type as singleton holder forget about lazy initalization and garbage collection!

Ricardo Ferreira said...

Generelly we should avoid the usage of singletons! Singletons generate less cohesive code and contribute to bad design if the usage was abused. I'm not saying the Singletons are bad in all cases! Just showing pro and contras!

Ricardo Ferreira said...

I like your post and it is very informative! Good Job!

VKJ said...

Thank you Ricardo Ferreira for your valuable comment

satya said...

whats the use of singleton on distributed system ?

Post a Comment

 
Copyright 2011 Java Online