Tuesday 9 July 2013

Various Singleton approaches in Java

Java Singleton

There are several approaches in Java to create a singleton class. The various methodologies and their pros and cons are discussed here:

1) Eager Initialization:

In case of eager initialization, the singleton is instantiated when the programs starts whether or not it gets used. The problem with this approach is that valuable resources are allocated whether or not they ever get used. If you are uncertain on whether your singleton object will be used or not and the singleton has a large memory footprint, this may not be a good choice.

public class Singleton {

    // Eager initialization happens here.
    static private Singleton instance = new Singleton();

    // Prevent instantiation by public.
    private Singleton() {
    }

    public static Singleton getInstance() {
        return instance;
    }
}

Eager initialization relies on the fact that the JVM will initialize the class members upon loading the class. And the class is loaded when it is first referenced.


2) Lazy Initialization:

In case of lazy initialization, the object only get instantiated on the first time the getInstance() method is called. This has the advantage of not allocating the resources unless it is actually needed. The problem with this approach is that the getInstance() method needs to be synchronized. Therefore there is a performance hit when acquiring the singleton on subsequent calls.

public class Singleton {

    static private Singleton instance = null;

    // Prevent instantiation by public.
    private Singleton() {
    }

    synchronized public static Singleton getInstance() {
        if (instance == null) {
            // Lazy initialization happens here
            // on the first call to this method.
            instance = new Singleton();
        }
        return instance;
    }

}

The subsequent calls for fetching the singleton object will have to go through the synchronization block which is a performance hit. This will also result in parallel threads in wait stage.


3) Lazy Initialization with double check:


This is a methodology is used to overcome the performance issue with lazy initialization. We do a double check to ensure that the subsequent calls for acquiring singleton object after its creation does not have to go through a synchronized block.

public class Singleton {


    private volatile Singleton instance = null;
    
    // Prevent instantiation by public.
    private Singleton() {
    }
public static Singleton getInstance() { if (instance == null) { synchronized(
Singleton.class) { if (instance == null) { instance = new Singleton (); } } } return instance; }
}

But this approach fails in a multiprocessor environment and is not recommended.
Further details : http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-toolbox.html

4) On Demand Initialization with a holder class:

This method relies on the JVM only intializing the class members upon first reference to the class. In this case, we have a inner class that is only referenced within the getInstance() method. This means SingletonHolder will get initialized on the first call to getInstance().

public class Singleton {

    // Prevent instantiation by public.
    private Singleton() {
    }

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    } 

    /**
     * Singleton implementation helper.
     */
    private static class SingletonHolder {
        // This gets initialized on first reference
        // to SingletonHolder.
        static final Singleton instance = new Singleton();
    }
}

In this case, the singleton object will not get allocated until it is used and we did not need to incur the overhead of a synchronized method call.
The only issue we have here is that a serialization/deserialization or by using reflection, we can create a new instance of this singleton class. For solving the serialization/deserialization scenario breaking the singleton, we can override readresolve() method. For handling the instance creation via reflection, all we can do is to enable java security manager property. This will restrict the access of private constructor via reflection.

5) Enum approach with Java 5:

There is one more, probably the best way to do it if you are using Java >= 1.5 according to 'Effetive Java' author 
Joshua Bloch. I personally feel that the above methodology(number 4) is the best approach among all. 
In Java 5 and above, you can use Enum – this way you get Singleton functionality easily and don’t have to think about serialization as you get it for free:


public enum YourSingleton {
INSTANCE;

public void doStuff(String stuff) {
System.out.println("Doing " + stuff);
}
}

Now you can use it and be completely sure it’s Singleton:
You can make call to the methods as following:
Singleton.INSTANCE.doStuff("some stuff");

4 comments:

  1. nice article...
    4th one is really tricky.
    5th ofcourse the best one...
    Thanks for this informative article..

    ReplyDelete
  2. @Pushkar: 5th one definitely serves the purpose but an enum is not meant for being a singleton class serving functional/computation methods. It should be just an enumeration representative. But if you see only purpose as important, then 5th one would serve you best. But in real time scenarios that I have encountered, approach 1 or 4 serves purpose (depending upon scenario).

    ReplyDelete
  3. good one yaar...really useful and got to know something new :)

    ReplyDelete