In this post, we will see about Singleton design pattern in java.
Singleton design pattern is one of the simplest design pattern but singleton property can be broken using multithreading, reflection, serialization etc, so you need to be careful while you create the singleton class.
Singleton design pattern restricts a class to create multiple objects so you can create only one instance of singleton class.Singleton classes are used for logging, database connections, caching and thread pool, .etc.
Singleton class
There are many ways to create singleton but it has few common steps.
-
- Make constructor private: You need to make the constructor private so you can not create instance of class from outside of the class.
- Provide static method to access object of singleton class: Create static method which will return object of singleton class.
- Create instance of same class as public static which will be returned by static method.
There are many ways to create Singleton class, we will see each one in detail.
Table of Contents
Eager initialization
Eager initialization is one of the simplest ways to create singleton.Object of the class is created once class is loaded into memory.It is done by creating object of the class when we declare reference variable.
Let’s understand with the help of example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package org.arpit.java2blog.singleton; public class EagerInitializationSingleton { private static final EagerInitializationSingleton instance = new EagerInitializationSingleton(); private EagerInitializationSingleton() { // private constructor } public static EagerInitializationSingleton getInstance() { return instance; } } |
Even if client does not need singleton object, still instance is created.If your singleton object is not resource intensive, you can still use it but in general, when you use singleton for connection pooling or database connections, it is resource intensive.
Lazy initialization
Lazy initialization is another way of creating singleton.Instead of creating object at time of variable declaration, we can create it in static method getInstance as below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package org.arpit.java2blog.singleton; public class LazyInitializationSingleton { private static LazyInitializationSingleton instance; private LazyInitializationSingleton() { // private constructor } public static LazyInitializationSingleton getInstance() { if(instance==null) { instance= new LazyInitializationSingleton(); } return instance; } } |
Above code will work fine in case of single-threaded system but in case of multithreading, you might end up creating more than one instance of the class.
Thread safe Singleton
The easiest way to create above class thread-safe is to make getInstance method singleton as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package org.arpit.java2blog.singleton; public class ThreadSafeSingleton { private static ThreadSafeSingleton instance; private ThreadSafeSingleton() { // private constructor } public static synchronized ThreadSafeSingleton getInstance() { if(instance==null) { instance= new ThreadSafeSingleton(); } return instance; } } |
Above approach will work fine and provide thread safety but there is performance cost associated with it as we have made whole method synchronized. Instead of making getInstance method, we can implement double check locking pattern.
Double check locking
Double check locking use synchronized block with extra null check to make sure only one instance is created for singleton class as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package org.arpit.java2blog.singleton; public class ThreadSafeSingletonDoubleCheck { private static volatile ThreadSafeSingletonDoubleCheck instance; private ThreadSafeSingletonDoubleCheck() { // private constructor } public static ThreadSafeSingletonDoubleCheck getInstance() { if(instance==null) { synchronized (ThreadSafeSingletonDoubleCheck.class) { if(instance==null) { instance= new ThreadSafeSingletonDoubleCheck(); } } } return instance; } } |
Why do you need double check locking? What can be problem with below code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public static synchronized ThreadSafeSingletonDoubleCheck getInstance() { if(instance==null) { synchronized (ThreadSafeSingletonDoubleCheck.class) { instance= new ThreadSafeSingletonDoubleCheck(); } } return instance; } |
Let’s say Thread T1 and T2 both found instance as null.Both T1 and T2 are waiting for class level lock.T1 takes the lock and creates the instance of ThreadSafeSingletonDoubleCheck and releases the lock. T2 takes the lock now and it too creates object of singleton which violates our requirement that’s why we require double check lock here.
Bill Pugh Singleton Implementation
Bill pugh singleton implementation is one of the best way to create singleton class. It makes use of static inner class to create singleon class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package org.arpit.java2blog.singleton; public class BillPughSingleton { private BillPughSingleton() { // private constructor } private static class SingletonHelper{ private static final BillPughSingleton INSTANCE = new BillPughSingleton(); } public static BillPughSingleton getInstance(){ return SingletonHelper.INSTANCE; } } |
When the singleton class is loaded, inner class is not loaded and hence it doesn’t create object of Singleton class when loading the class. Inner class is created only when getInstance() method is called. So it looks like a eager initialization at first, but it is actually lazy initialization.
Create singleton using Enum
As Java Enum are global constants and loaded only once. Joshua Bloch suggested that Enum is best candidate for singleton design pattern. Please note that Java Enum does not allow lazy initialazation, so even if you do not use singleton, it will still be loaded.
Enum exmaple:
1 2 3 4 5 6 7 8 9 |
package org.arpit.java2blog.singleton; public enum SingletonEnum { INSTANCE; // Write other methods } |
As Enum does not provide any explicit constructor, you can not create multiple instance of sinlgeton class even with reflection.
Testing singleton with Reflection
You can easily destroy singleton with the help of reflection for all above implementations excpet Enum.Reflection is powerful mechanism to instantiate the objects.
Let’s understand with the help of example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package org.arpit.java2blog.singleton; import java.lang.reflect.Constructor; public class ReflectionSingletonTest { public static void main(String[] args) { BillPughSingleton instance1 = BillPughSingleton.getInstance(); BillPughSingleton instance2 = null; try { Constructor[] constructors = BillPughSingleton.class.getDeclaredConstructors(); for (Constructor constructor : constructors) { //Below code will destroy the singleton pattern constructor.setAccessible(true); instance2 = (BillPughSingleton) constructor.newInstance(); break; } } catch (Exception e) { e.printStackTrace(); } System.out.println("Hashcode of instance1: "+instance1.hashCode()); System.out.println("Hashcode of instance2: "+instance2.hashCode()); } } |
When you run above program, you will get below output:
Hashcode of instance2: 1442407170
As you can see, Hashcode of instance1 and instance2 are different, so we are able to create two instance of singleton class.
You can restrict the scenario by throwing Runtime Exception when reflection tries to create the instance of object second time as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package org.arpit.java2blog.singleton; public class BillPughSingleton { private BillPughSingleton() { // private constructor if(SingletonHelper.INSTANCE!=null) { throw new RuntimeException("You can not create object of singleton class twice"); } } private static class SingletonHelper{ private static final BillPughSingleton INSTANCE = new BillPughSingleton(); } public static BillPughSingleton getInstance(){ return SingletonHelper.INSTANCE; } } |
When you run ReflectionSingletonTest now, you will get below output.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.arpit.java2blog.singleton.ReflectionSingletonTest.main(ReflectionSingletonTest.java:14)
Caused by: java.lang.RuntimeException: You can not create object of singleton class twice
at org.arpit.java2blog.singleton.BillPughSingleton.(BillPughSingleton.java:10)
… 5 more
Hashcode of instance1: 1028566121
Exception in thread “main” java.lang.NullPointerException
at org.arpit.java2blog.singleton.ReflectionSingletonTest.main(ReflectionSingletonTest.java:21)
As you can see, above program throws Runtime Exception, when reflection tries to create object of singleton class twice.
Testing singleton with Serialization
When you serialize and deserialize the object of the singleton class, you should get the same object.
Let’s see if we are going to get the same object or not with the help of simple example.
Let’s first make BillPughSingleton class Serializable.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package org.arpit.java2blog.singleton; import java.io.Serializable; public class BillPughSingleton implements Serializable{ private static final long serialVersionUID = 2088778914384963252L; private BillPughSingleton() { // private constructor if(SingletonHelper.INSTANCE!=null) { throw new RuntimeException("You can not create object of singleton class twice"); } } private static class SingletonHelper{ private static final BillPughSingleton INSTANCE = new BillPughSingleton(); } public static BillPughSingleton getInstance(){ return SingletonHelper.INSTANCE; } } |
Let’s create SingletonSerializedTest to test serialization scenario.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package org.arpit.java2blog.singleton; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; public class SingletonSerializedTest { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { BillPughSingleton instance1 = BillPughSingleton.getInstance(); // Serialize the object ObjectOutput out = new ObjectOutputStream(new FileOutputStream( "singleton.ser")); out.writeObject(instance1); out.close(); // deserialize the object ObjectInput in = new ObjectInputStream(new FileInputStream( "singleton.ser")); BillPughSingleton instance2 = (BillPughSingleton) in.readObject(); in.close(); System.out.println("Hashcode of instance1: "+instance1.hashCode()); System.out.println("Hashcode of instance2: "+instance2.hashCode()); } } |
When you run above program, you will get below output.
Hashcode of instance2: 295530567
As you can see, Hashcode of instance1 and instance2 are different, so we are able to create two instances of singleton class with help of serialization.
Implement readResolve method to overcome above scenario as below.
1 2 3 4 5 |
protected Object readResolve() { return getInstance(); } |
When you run SingletonSerializedTest now, you will get below output.
Hashcode of instance2: 589431969
Testing singleton with Cloning.
In case, if your singleton class implements clonable interface, you need to override clone method and throw CloneNotSupportedException from it.
1 2 3 4 5 6 |
public Object clone() throws CloneNotSupportedException { return new CloneNotSupportedException("You can not clone object of Singleton class "); } |
Let’s create CloningSingleonTest to create cloning scenario.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package org.arpit.java2blog.singleton; public class CloningSingleonTest { public static void main(String[] args) throws CloneNotSupportedException { BillPughSingleton instance1 = BillPughSingleton.getInstance(); BillPughSingleton instance2=(BillPughSingleton) instance1.clone(); System.out.println("Hashcode of instance1: "+instance1.hashCode()); System.out.println("Hashcode of instance2: "+instance2.hashCode()); } } |
When you run above program, you will get below output.
at org.arpit.java2blog.singleton.CloningSingleonTest.main(CloningSingleonTest.java:7)
That’s all about Singleton Design pattern.