Java Code Geeks

Friday, June 4, 2010

Its all about the Neo - the singleton

Singleton is one of the most commonly used design pattern. However, a great deal of attention is required to make it right.
The invariant of singleton is to make sure - there is one instance of the object present always. This sounds simple and looks
like make the constructor private and have a private static final instance member variable is enough to create a singleton. But what if the object needs to be Serializable ? The moment someone makes the singleton object serializable, upon deserialization, you get another instance of it. So we need to provide readResolve() throws ObjectStreamException method to fix that.
The simple implementation of singleton is

public class SingleObject {

private static SingleObject INSTANCE = new SingleObject();
private SingleObject()
{
}
public static SingleObject getInstance() {
return INSTANCE;
}
}

This is proper but as the INSTANCE is a static field, so the instance of the Singleton object will be created always.
The other implementation is lazy initialization (anything that is lazy, pay special attention to the threading)

public class SingleObject {

private static SingleObject INSTANCE = null;
private SingleObject()
{
}
public static SingleObject getInstance() {
if (null == INSTANCE ) {
INSTANCE = new SingleObject();
}
return INSTANCE;
}
}

Looks to be okay but this one is broken in multi threaded system, if two threads calls the same getInstance method, the check-and-create pattern might produce two Instances.

One simple fix is -

public static synchronized SingleObject getInstance() {
if (null == INSTANCE ) {
INSTANCE = new SingleObject();
}
return INSTANCE;
}

but then, the penalty of getInstance calling is high now, whether the object is already created or not, always synchonization is required here and it will make the application slow. Ideally, only when object is not present, it needs to be created and hence synchronized. Instead in this case, the getInstance method is synchronized, so there is a performance penalty always
whether the object is already created or not.
The fix is little tricky and now the singleton coding becomes interesting -

public class SingleObject {

private volatile static SingleObject INSTANCE = null;
private SingleObject()
{
}
public static SingleObject getInstance() {
if (null == INSTANCE ) {
synchronized (SingleObject.class) {
if (null == INSTANCE) {
INSTANCE = new SingleObject();
}
}
}
return INSTANCE;
}
}


As we can see now, there are plenty of things to worry about, the volatile variable and the double check to ensure multiple threads work properly.

If we do not want to use synchronized at all and yet make it thread safe - use the "lazy initialization holder class" idiom as mentioned by Joshua Bloch.


public class SingleObject {

private SingleObject() {
System.out.println("It got created");
}
private static class ClassHolder {
static final SingleObject instance = new SingleObject();
}
public static SingleObject getInstance() {
return ClassHolder.instance;
}
public static void someOtherFunc() {
System.out.println("Some other func can also be static ?");
}
}

In this way, we can achieve thread safety, because for the first time, the getInstance method will be called, it will access
the class ClassHolder causing it to load and initiaze the instance variable.
This is a powerful method and can be very useful for any lazy property initialization of a class.

However, there is now an easy way to create singleton since JDK 1.5 and it is called Single value enum strategy. People who follows Joshua Block and Effective Java knows what I am talking about.


public enum SingleObjectEnum {

INSTANCE;
Public void othermethods…
}

Now, SingleObjectEnum.INSTANCE is definitely a singleton and multi-threading, serialization etc is not developers headache as it comes from JVM itself.

3 comments:

Unknown said...

Hey Shamik,

Long time since we have talked. I’m now the social media strategist for HPSWS. Great that you have started blogging.

Michael Procopio

Shamik Majumdar said...

Thanks for reading my Blog Michael. Hopefully someday I will completely understand the power of social media.

Richard Sequeira said...

Hi Shamik,

Great blog! Learnt a new way of creating singleton.

Richard