Singleton Design Pattern

Singleton Design Pattern

Overview

Singleton pattern is a creational design pattern which ensure that a class has only one instance throughout application and which can be access via global access point.

There are many ways to create Singleton Design pattern. Each way has its own benefit and drawbacks. From the definition, although It seems simple, but muti-threaded environment add more complexities to it. Below are the different ways of creating the Singleton pattern in Java:

  • Eager initialization
  • Static block initialization
  • Lazy initialization
  • ThreadSafe Lazy initialization
  • ThreadSafe Double check Lazy initialization
  • Bill Pugh Singleton
  • Enum Singleton

Singleton pattern using Eager initialization

This is the quite basic implementation of Singleton patter. Here we are initializing the instance at the time of loading of class itself.

 1public class EagerInitializationSingleton {
 2
 3    private static EagerInitializationSingleton instance = new EagerInitializationSingleton();
 4
 5    private EagerInitializationSingleton() {
 6    }
 7
 8    public static EagerInitializationSingleton getInstance() {
 9        return instance;
10    }
11}

Drawbacks:

  • Object will be created and consume memory even nobody is using this.
  • Multiple objects can be created using Serialization
  • Multiple objects can be created using Reflection

Singleton pattern using Static block initialization

It's the alternative implementation of Eager initialization, instead of initializing the static variable at the time of declaration, We are initializing it in static block.

 1
 2public class StaticBlockInitializationSingleton {
 3
 4    private static StaticBlockInitializationSingleton instance;
 5
 6    static {
 7        try {
 8            instance = new StaticBlockInitializationSingleton();
 9        } catch (Exception e) {
10            System.out.println(e.getCause());
11        }
12    }
13
14    private StaticBlockInitializationSingleton() {
15    }
16
17    public static StaticBlockInitializationSingleton getInstance() {
18        return instance;
19    }
20}

Drawbacks:

  • Object will be created and consume memory even nobody is using this.
  • Multiple objects can be created using Serialization
  • Multiple objects can be created using Reflection

Singleton pattern using Lazy initialization

Lazy initialization implementation help us creating the object at the time of first use. So, if nobody wants this object, object will never be created.

 1public class LazyInitializationSingleton {
 2
 3    private static LazyInitializationSingleton instance;
 4
 5    private LazyInitializationSingleton() {
 6    }
 7
 8    public static LazyInitializationSingleton getInstance() {
 9        if(instance == null)
10            instance = new LazyInitializationSingleton();
11        return instance;
12    }
13}

Drawbacks:

  • Multiple object can be created in case of multi-threaded environment. e.g. if two thread simultaneously call getInstance(), both will see instance as null and create new object.
  • Multiple objects can be created using Serialization
  • Multiple objects can be created using Reflection

Singleton pattern using ThreadSafe Lazy initialization

This is the thread safe implementation of LazyInitializationSingleton. Here we have added synchronized which will make sure only one thread will call it at a time.

 1public class ThreadSafeLazyInitializationSingleton {
 2
 3    private static ThreadSafeLazyInitializationSingleton instance;
 4
 5    private ThreadSafeLazyInitializationSingleton() {
 6    }
 7
 8    public static synchronized ThreadSafeLazyInitializationSingleton getInstance() {
 9        if(instance == null)
10            instance = new ThreadSafeLazyInitializationSingleton();
11        return instance;
12    }
13}

Drawbacks:

  • Although it's thread safe, by this thread safety has a higher cost as you can see synchronized is at method level, if object already created, all consecutive call will still pass through synchronized which is expensive as it put a lock on every request and refresh the thread context.
  • Multiple objects can be created using Serialization
  • Multiple objects can be created using Reflection

Singleton pattern using ThreadSafe Double check Lazy initialization

Double check Lazy initialization is further enhancement on previous one. As you can see instance == null is checked twice, outside synchronized and inside synchronized. instance == null inside synchronized prevent creation of two instance when two thread simultaneously try to create object. instance == null helps in performance when object already created and some client try to get the object, then this first null check will return the object without going through the synchronized.

Note

Here Object is backed by volatile which instruct the JVM not to store the object reference in thread memory by instead flush to main memory and also instruct each thread to look for the object from main memory. Hence it make sure that changes made by one thread are immediately visible to others.

 1public class ThreadSafeDoubleCheckLazyInitializationSingleton {
 2
 3    private static volatile ThreadSafeDoubleCheckLazyInitializationSingleton instance;
 4
 5    private ThreadSafeDoubleCheckLazyInitializationSingleton() {
 6    }
 7
 8    public static ThreadSafeDoubleCheckLazyInitializationSingleton getInstance() {
 9        if (instance == null) {
10            synchronized (ThreadSafeDoubleCheckLazyInitializationSingleton.class) {
11                if (instance == null) {
12                    instance = new ThreadSafeDoubleCheckLazyInitializationSingleton();
13                }
14            }
15        }
16
17        return instance;
18    }
19}

Drawbacks:

  • Before java 1.5, JVM has a bug around visibility of changes made by one thread to other thread. Although above example cause no issue since java 1.5 but problematic in earlier version.
  • Multiple objects can be created using Serialization
  • Multiple objects can be created using Reflection

Singleton pattern using Bill Pugh Singleton

Bill Pugh Singleton provide ultimate solution for the singleton without using any synchronized or volatile keyword. It make use of JVM functionality to which make sure to intialize the static classes or static inner classes before making the class ready to use. So here, object is created inside a staic inner class which will only initialized during first use and once fully initialize , only then client can use it.

 1public class BillPughSingleton {
 2    public BillPughSingleton() {
 3    }
 4
 5    public static BillPughSingleton getInstance() {
 6        return SingletonHelper.INSTANCE;
 7    }
 8
 9    private static class SingletonHelper {
10        private static final BillPughSingleton INSTANCE = new BillPughSingleton();
11    }
12}

Singleton pattern using Enum Singleton

Enums are another approach to create Singleton Object quite easily and with thread safety.

1public enum  EnumSingleton {
2    INSTANCE;
3
4    public static void doSomething(){
5        //do something
6    }
7
8}

How to test

 1public class Client {
 2    public static void main(String[] args) {
 3        //Eager initialization
 4        System.out.println("Eager initialization");
 5        System.out.println(EagerInitializationSingleton.getInstance());
 6        System.out.println(EagerInitializationSingleton.getInstance());
 7
 8        //Static block initialization
 9        System.out.println("StaticBlock initialization");
10        System.out.println(StaticBlockInitializationSingleton.getInstance());
11        System.out.println(StaticBlockInitializationSingleton.getInstance());
12
13        //Lazy initialization
14        System.out.println("Lazy initialization");
15        System.out.println(LazyInitializationSingleton.getInstance());
16        System.out.println(LazyInitializationSingleton.getInstance());
17
18        //ThreadSafe Lazy initialization
19        System.out.println("ThreadSafe Lazy initialization");
20        System.out.println(ThreadSafeLazyInitializationSingleton.getInstance());
21        System.out.println(ThreadSafeLazyInitializationSingleton.getInstance());
22
23        //ThreadSafe Double check Lazy initialization
24        System.out.println("ThreadSafe Double check Lazy initialization");
25        System.out.println(ThreadSafeDoubleCheckLazyInitializationSingleton.getInstance());
26        System.out.println(ThreadSafeDoubleCheckLazyInitializationSingleton.getInstance());
27
28        //Bill Pugh Singleton
29        System.out.println("Bill Pugh Singleton");
30        System.out.println(BillPughSingleton.getInstance());
31        System.out.println(BillPughSingleton.getInstance());
32
33        //Enum Singleton
34        System.out.println("Enum Singleton");
35        System.out.println(EnumSingleton.INSTANCE);
36        System.out.println(EnumSingleton.INSTANCE);
37    }
38}

Output Will be :

 1Eager initialization
 2com.learn.designpattern.creational.singleton.EagerInitializationSingleton@3f0ee7cb
 3com.learn.designpattern.creational.singleton.EagerInitializationSingleton@3f0ee7cb
 4
 5StaticBlock initialization
 6com.learn.designpattern.creational.singleton.StaticBlockInitializationSingleton@7d417077
 7com.learn.designpattern.creational.singleton.StaticBlockInitializationSingleton@7d417077
 8
 9Lazy initialization
10com.learn.designpattern.creational.singleton.LazyInitializationSingleton@35bbe5e8
11com.learn.designpattern.creational.singleton.LazyInitializationSingleton@35bbe5e8
12
13ThreadSafe Lazy initialization
14com.learn.designpattern.creational.singleton.ThreadSafeLazyInitializationSingleton@5a39699c
15com.learn.designpattern.creational.singleton.ThreadSafeLazyInitializationSingleton@5a39699c
16
17ThreadSafe Double check Lazy initialization
18com.learn.designpattern.creational.singleton.ThreadSafeDoubleCheckLazyInitializationSingleton@56cbfb61
19com.learn.designpattern.creational.singleton.ThreadSafeDoubleCheckLazyInitializationSingleton@56cbfb61
20
21Bill Pugh Singleton
22com.learn.designpattern.creational.singleton.BillPughSingleton@129a8472
23com.learn.designpattern.creational.singleton.BillPughSingleton@129a8472
24
25Enum Singleton
26INSTANCE
27INSTANCE

Break Singlton using Reflection

Reflection is the feature of java which is capable of breaking most concept in java e.g. field visibility, methods visibility. below example shows how it breaks the certain Singleton implementation.

 1import java.lang.reflect.Constructor;
 2
 3public class ReflectionSingletonTest {
 4
 5    public static void main(String[] args) {
 6        EagerInitializationSingleton instanceOne = EagerInitializationSingleton.getInstance();
 7        EagerInitializationSingleton instanceTwo = null;
 8        try {
 9            Constructor[] constructors = EagerInitializationSingleton.class.getDeclaredConstructors();
10            for (Constructor constructor : constructors) {
11                //Below code will destroy the singleton pattern
12                constructor.setAccessible(true);
13                instanceTwo = (EagerInitializationSingleton) constructor.newInstance();
14                break;
15            }
16        } catch (Exception e) {
17            e.printStackTrace();
18        }
19        System.out.println(instanceOne.hashCode());
20        System.out.println(instanceTwo.hashCode());
21    }
22
23}

Break Singleton using Serialization

Serialization is another way to break Singleton but luckily we have a way to make singleton Serialization safe which you can see in next section.

 1import java.io.*;
 2
 3public class SingletonSerializedTest {
 4
 5    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
 6        SerializedSingleton instanceOne = SerializedSingleton.getInstance();
 7        ObjectOutput out = new ObjectOutputStream(new FileOutputStream(
 8                "filename.ser"));
 9        out.writeObject(instanceOne);
10        out.close();
11        
12        //deserailize from file to object
13        ObjectInput in = new ObjectInputStream(new FileInputStream(
14                "filename.ser"));
15        SerializedSingleton instanceTwo = (SerializedSingleton) in.readObject();
16        in.close();
17        
18        System.out.println("instanceOne hashCode="+instanceOne.hashCode());
19        System.out.println("instanceTwo hashCode="+instanceTwo.hashCode());
20        
21    }
22
23}

Serialization Fix for Singleton

 1import java.io.Serializable;
 2
 3public class SerializedSingleton implements Serializable {
 4
 5    private static final long serialVersionUID = -7604766932017737115L;
 6
 7    private SerializedSingleton(){}
 8    
 9    private static class SingletonHelper{
10        private static final SerializedSingleton instance = new SerializedSingleton();
11    }
12    
13    public static SerializedSingleton getInstance(){
14        return SingletonHelper.instance;
15    }
16
17    protected Object readResolve() {
18        return getInstance();
19    }
20    
21}

Posts in this Series

comments powered by Disqus