Design Patterns - Singleton

We will start with what Singleton design pattern is and various ways to create a singleton instance of a class e.g lazy initialization, reflection and serialization safe Singleton.

1. What is Singleton?

Singleton is a design pattern which comes under the category creational pattern. Sometimes, it is important to have one instance of class or we can say, it provide single global entry point to the object.

2. How can we create a Singleton?

There are many ways to create Singleton. Each one of them have their pros and cons.

  1. Eager Initialization
  2. Lazy Initialization
  3. Enum based Singleton

2.1. Eager Initialization

In this approach, we eagerly creates an instance of Singleton object during the class load time.

public class Singleton {
private static final Singleton INSTANCE = new Singleton();

// Private constructor
private Singleton() {}

public static final getInstance() {
return INSTANCE;
}
}

2.2. Lazy Initialization

In this approach, we lazily creates an instance of Singleton during getInstance method call. We have to either synchorized whole method or take a mutex lock in getInstance method which is also called double-check locking to make it thread safe.

public class Singleton {
private static Singleton INSTANCE = null;
private static final Object MUTEX = new Object();

// Private constructor
private Singleton() {}

public static final getInstance() {
if (INSTANCE == null) {
synchornized(MUTEX) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}

return INSTANCE;
}
}

The problem with double-check locking is that it is broken.

There is an article explains why it is broken.

2.3. Enum based Singleton

The last solution is taken from the Effective Java book (Item 3) by Joshua Block and uses an enum instead of a class. At the time of writing, this is considered to be the most concise and safe way to write a singleton.

3. Reflection and Serialization safe Singleton

Eager and Lazy initialzation based approaches explained above are prone to reflection and serialization. To make it safer, we can follow below approach.

public class Singleton {
private static class SingletonInstanceHolder {
private static int MODCOUNT = 0;
private static Singleton INSTANCE = null;
private static final Object MUTEX = new Object();

static {
if (INSTANCE == null) {
synchronized (MUTEX) {
if (INSTANCE == null)
try {
INSTANCE = new Singleton();
} catch (IllegalAccessException e) {
// This is just to show as example
// Don't follow it for production code
e.printStackTrace();
}
}
}
}
}

private Singleton() throws IllegalAccessException {
if(SingletonInstanceHolder.MODCOUNT > 0) {
throw new IllegalAccessException("Multiple instance");
}

SingletonInstanceHolder.MODCOUNT++;
}

public static final Singleton getInstance() {
return SingletonInstanceHolder.INSTANCE;
}

// Avoiding duplicate objects with serialization
public Object readResolve() {
return getInstance();
}
}

We have defined readResolve method to use getInstance method to resolve it to correct singleton instance during Serialization/ Deserialization. In Singleton constructor, we are checking the MODCOUNT, if it is more than 1, we are throwing exception and preventing creation of another object using reflection (making constructor public).

The below test code and the exception trace just explains the above to reasoning.

public class SingletonTest {
public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException,InvocationTargetException {

Class demo = Class.forName("singleton.Singleton");
Constructor con = demo.getDeclaredConstructor();
con.setAccessible(true);

for(int i=0; i<10; i++) {
Singleton s1 = (Singleton) con.newInstance();
System.out.println(s1.toString());
}
}
}

The above code when run will throw following InvocationException. It shows that the Singleton class's object will be created only once and then it will throw exception if tried to called constructor multiple times even with reflection.

Exception in thread "main" java.lang.reflect.InvocationTargetException
 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
 at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
 at singleton.SingletonTest.main(SingletonTest.java:15)
Caused by: java.lang.IllegalAccessException: Multiple instance
 at singleton.Singleton.<init>(Singleton.java:29)
 ... 5 more


Tags: Design Patterns, Singleton design pattern, Reflection and Serialization safe Singleton, Lazy initialization Singleton pattern, Java

← Back home