Singleton Design Pattern In Java With All Scenarios

 Singleton Design Pattern With All Scenarios

In this article we will go through all the scenarios of the Singleton pattern to make it crystal clear. From the definition, it seems to be a very simple design pattern but when it comes to implementation, it creates a lot of implementation concerns. Also, the implementation of Java Singleton pattern has always been a controversial topic among developers. Here we will learn about Singleton Design Pattern in Java with all Scenarios, different ways to implement Singleton design pattern and some of the best practices for its usage.

Sometimes we get the requirement for some classes to have exactly one instance. There are many occasions when we need only one instance of the Object and if we instantiate more than one, we’ll run into all sorts of problems like incorrect program behavior, overuse of resources, or inconsistent results. In this article, we will learn about ‘Singleton Design Pattern in Java with all Scenarios’ in detail.

Table of Contents (Click on links below to navigate) [hide]

What is a Singleton Design Pattern ?

There are only two points in the definition of a singleton design pattern,

1) There should be only one instance allowed for a class and
2) We should allow global point of access to that single instance.

Now, lets discuss Singleton Design Pattern in Java with all Scenarios in deep.

Thread-Safe Singleton (Eager Initialization)

In eager initialization instance is created at the time of class loading. We will not have any thread safety issue if we choose to go with eager initialization. If your application always creates and uses an instance of the Singleton or the overhead of creation and runtime aspects of the Singleton are not burdensome, you may want to create your Singleton eagerly, like this:Thread Safe-Singleton : Eager Initialization

public class Singleton{
	
   //Eager Initialization
   //Below instance is guaranteed to be thread safe.

   private static Singleton uniqueInstance= new Singleton();

   private Singleton() { }

   public static Singleton getInstance() {

    //We have already got an instance, so just return it.

    return uniqueInstance;

   }

}

Using this approach, we rely on the JVM to create the unique instance of the Singleton when the class is loaded. The JVM guarantees that the instance will be created before any thread accesses the static uniqueInstance variable. Now here is one catch! We have to think about thread safety. In that case, we go with lazy initialization.

There are some examples where Singleton pattern violation situation can be found in thread-safe environment. However we will use the hash code comparison technique to verify the equality of two objects. If hash code values of two objects are equal, those objects must be equal.

Singleton Violation on Using Reflection

Using reflection we can set the private constructor to become accessible at runtime as shown in the example below.Singleton Violation

package com.dev.dp.creational.singleton;

import java.lang.reflect.Constructor;

public class SingletonR {
	
	public static SingletonR instance= new SingletonR();
	
	private SingletonR() {
		System.out.println("creating instance.....");
		
	}
	
	public static SingletonR getInstance() {
		return instance;
	}

	public static void main(String[] args) throws Exception{
		SingletonR s1 = SingletonR.getInstance();
		SingletonR s2 = SingletonR.getInstance();
		System.out.println("Hashcode of Object s1: " +s1.hashCode());
		System.out.println("Hashcode of Object s2: " +s2.hashCode());
		
		Class clazz = Class.forName("com.dev.dp.creational.singleton.SingletonR");
		Constructor<SingletonR> ctr= clazz.getDeclaredConstructor();
		ctr.setAccessible(true);
		SingletonR s3 = ctr.newInstance();
		System.out.println("Hashcode of Object s3: " +s3.hashCode());

	}
	
} 

Output :Output

creating instance.....
Hashcode of Object s1: 366712642
Hashcode of Object s2: 366712642
creating instance.....
Hashcode of Object s3: 1829164700 

From the above output it is clear that using reflection singleton violation can happen.

How to Fix Violation

Throw Runtime Exception if someone tries to make instance in case one instance already exists. Below code will go into the private constructor of the Singleton class accordingly.Constructor code of class SingletonR

private SingletonR() {
		System.out.println("creating instance.....");
		if(instance != null) {
			throw new RuntimeException("Can't create instance. Please use getInsance() to create it.");
		}	
} 

Output After fix

Output After Fix

creating instance.....
Hashcode of Object s1: 366712642
Hashcode of Object s2: 366712642
creating instance.....
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
	at java.lang.reflect.Constructor.newInstance(Unknown Source)
	at com.dev.dp.creational.singleton.SingletonR.main(SingletonR.java:29)
Caused by: java.lang.RuntimeException: Can't create instance. Please use getInsance() to create it.
	at com.dev.dp.creational.singleton.SingletonR.<init>(SingletonR.java:12)
	... 5 more 
 

Singleton Violation on Object Cloning:

If we try to make instance by cloning it, the generated hash code of cloned copy doesn’t match with the actual object so it also violates the Singleton principle.Singleton Violation

package com.dev.dp.creational.singleton;

public class SingletonC implements Cloneable{
	
	public static SingletonC instance= new SingletonC();
	
	private SingletonC() {
		System.out.println("creating instance.....");
	}
	
	public static SingletonC getInstance() {
		return instance;
	}

	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
	public static void main(String[] args) throws Exception{
		SingletonC s1 = SingletonC.getInstance();
		SingletonC s2 = SingletonC.getInstance();
		System.out.println("Hashcode of Object s1: " +s1.hashCode());
		System.out.println("Hashcode of Object s2: " +s2.hashCode());
		
		SingletonC s3 = (SingletonC)s2.clone();
		System.out.println("Hashcode of Object s3: " +s3.hashCode());

	}	
}

Output:Output

creating instance.....
Hashcode of Object s1: 366712642
Hashcode of Object s2: 366712642
Hashcode of Object s3: 1829164700 

How to Fix Violation

Throw CloneNotSupportedException from the clone () method if someone tries to make another instance of it. Add below code in clone() method of above SingletonR class.Updated code of clone() method

protected Object clone() throws CloneNotSupportedException {
		if(instance != null) {
			throw new CloneNotSupportedException("Can't create instance. Please use getInsance() to create it.");
		}
		return super.clone();
} 

Output After fix

Output After Fix

creating instance.....
Hashcode of Object s1: 366712642
Hashcode of Object s2: 366712642
Exception in thread "main" java.lang.CloneNotSupportedException: Can't create instance. Please use getInsance() to create it.
	at com.dev.dp.creational.singleton.SingletonC.clone(SingletonC.java:17)
	at com.dev.dp.creational.singleton.SingletonC.main(SingletonC.java:28) 

Singleton Violation on Serialization/Deserialization

When we serialize an object and deserialize it again there are different hash code values generated as shown in the example below. Therefore our Singleton principle breaks in case of object serialization/deserialization also.Singleton Violation

package com.dev.dp.creational.singleton;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SingletonS implements Serializable{
	
	public static SingletonS instance= new SingletonS();
	
	private SingletonS() {
		System.out.println("creating instance.....");
	}
	
	public static SingletonS getInstance() {
		return instance;
	}

	public static void main(String[] args) throws Exception{
		SingletonS s1 = SingletonS.getInstance();
		SingletonS s2 = SingletonS.getInstance();
		System.out.println("Hashcode of Object s1: " +s1.hashCode());
		System.out.println("Hashcode of Object s2: " +s2.hashCode());
		
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/tmp/s2.ser"));
		oos.writeObject(s2);
		
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/tmp/s2.ser"));
		SingletonS s3= (SingletonS)ois.readObject();
		
		System.out.println("Hashcode of Object s3: " +s3.hashCode());

	}	
}

Output 

Output

creating instance.....
Hashcode of Object s1: 2055281021
Hashcode of Object s2: 2055281021
Hashcode of Object s3: 772777427 

How to Fix Violation

Implement a new readResolve () method in the Singleton class as shown below.readResolve( ) method

private Object readResolve() {
		System.out.println("Applying readResolve()......");
		return SingletonS.getInstance();
}

Output After fix

Output After Fix

creating instance.....
Hashcode of Object s1: 2055281021
Hashcode of Object s2: 2055281021
Applying readResolve()......
Hashcode of Object s3: 2055281021 

Singleton in Multithreaded Environment:

Singleton will work properly in multi-threaded environment only if eager instantiation has been done because in this case instance creation will happen at the time of class loading only. But for Lazy instantiation we will have to take care of multiple things. If we want to delay the instantiation because of cost, we will have to go with lazy.

Lazy vs Eager Initialization:

Lazy initialization will be beneficial when we want to delay the initialization until it is not needed. On the other hand, if we use eager initialization and if initialization fails there is no chance to get the instance further while in lazy initialization we may get it in second chance. In Lazy initialization we will not get instance until we call getInstance method while in eager initialization it creates instance at the time of class loading itself.

Following code demonstrates the behavior of Singleton instance when two threads are getting executed by comparing their hash code values. Be careful while running the following code as it will work only in Java 8 and later versions. Moreover we have used Method Reference in the code.Singleton in Lazy Initialization

package com.dev.dp.creational.singleton;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class SingletonT {

	private static SingletonT instance=null; //lazy initialization
	
	private SingletonT(){
		System.out.println("Creating...");
	}
	
	public static SingletonT getInstance(){
		if (instance == null) {
			instance = new SingletonT();
		}
		return instance;
	}
	
	static void useSingleton(){
		SingletonT singleton = SingletonT.getInstance();
		System.out.println("Hashcode of Singleton Object: "+singleton.hashCode());
	}
	
	public static void main(String[] args) throws Exception {
		ExecutorService service = Executors.newFixedThreadPool(2);
		service.submit(SingletonT::useSingleton);
		service.submit(SingletonT::useSingleton);
		service.shutdown();
	}	
}

Output 

Output

//Output On running first time

Creating...
Object : singleton, Hashcode: 1598725298
Object : singleton, Hashcode: 1598725298

//Output On running second time

Creating...
Creating...
Object : singleton, Hashcode: 1598725298
Object : singleton, Hashcode: 2124340618

//Output On running third time

Creating...
Object : singleton, Hashcode: 1598725298
Object : singleton, Hashcode: 1598725298 
 
 

Synchronizing method

As shown by the output of the program, It is noticeable that in multithreaded environment sometimes Singleton principle works while sometimes it violates as multiple threads are trying to create instance. Therefore we need to synchronize the getInstance () method as shown below.Synchonized getInstance() method

public static synchronized SingletonT getInstance(){
		if (instance == null) {
			instance = new SingletonT();
		}
		return instance;
	} 

Synchronizing block of code

After applying synchronize keyword in the getInstance () method the program may execute properly without any issue but in Java instead of synchronizing whole method we can synchronize only the block of code which is affected while creating instance to escape the extra overhead as below.synchronized block of code

public static SingletonT getInstance(){
		if (instance == null) {
			synchronized (SingletonT.class) {
				instance = new SingletonT();
			}
		}
		return instance;
} 

Double Checked Locking

Now from the above code we have narrowed down the scope of synchronization for performance reasons. Notice that if a thread at line # 2 notices that instance is null and then it gets the lock of object at line # 3. At the same time if another thread already has the lock it will create the instance. So to make sure no other thread has already acquired the lock we will apply one more check after acquiring the lock as shown below. This technique is called Double Checked Locking. With double-checked locking, we first check to see if an instance is created, and if not, then we synchronize. This way, we only synchronize the first time through, just what we want.Double Checked Locking

public static SingletonT getInstance(){
		if (instance == null) {   //check1
			synchronized (SingletonT.class) {
				if (instance == null) {   //check2
					instance = new SingletonT();
				}
			}
		}
		return instance;
} 
 

In rare cases, double-checked locking also breaks the Principle of Singleton.

Java runtime publishes half initialized variable. To illustrate, suppose 2 threads thread1 & thread2 are entering into the code it goes through the line # 2 to line # 31 and created the instance. Furthermore, at the same time thread 2 enters and it knows that there is something in variable named as ‘instance’ (since it is at half initialized state) and it returns the same from line # 9. Therefore, Singleton principle breaks.

***Note : Double-checked locking doesn’t work in Java 1.4 or earlier! Unfortunately, in Java version 1.4 and earlier, many JVMs contain implementations of the volatile keyword that allow improper synchronization for double-checked locking. If you must use a JVM earlier than Java 5, consider other methods of implementing your Singleton. Although I guess nobody might be using JVM earlier than Java5 but I have mentioned this point for your knowledge purpose only. Also, you may take it as a point of improvement in Java 5 enhancements.

Using volatile keyword

To address above situation, use volatile keyword at the time of instance declaration. Value of volatile variable will be published only when the change completes. Change to write operation happens before read operation in volatile variable. In fact, all threads will see the same value of variable.Use of volatile Keyword

private static volatile SingletonT instance=null; //lazy initialization

If performance is an issue in using getInstance() method then this method of implementing the Singleton can drastically reduce the overhead.

Holder Class (Bill Pugh Method) 

Bill Pugh came up with a different approach to create the Singleton class using an inner static helper class as below.Bill Pugh Singleton

package com.dev.dp.creational.singleton;

public class SingletonH {
	
	private SingletonH() {
		System.out.println("Creating.....");
	}
	
	static class Holder{
		static final SingletonH INSTANCE= new SingletonH(); //lazy
	
	}
	
	public static SingletonH getInstance() {
		return Holder.INSTANCE;
	}

	public static void main(String[] args) {

		SingletonH s1= SingletonH.getInstance();
		SingletonH s2= SingletonH.getInstance();
		SingletonH s3= SingletonH.getInstance();
		
		System.out.println("Hashcode of Object s1: " +s1.hashCode());
		System.out.println("Hashcode of Object s2: " +s2.hashCode());
		System.out.println("Hashcode of Object s3: " +s3.hashCode());

	}

} 

Output

Output

Creating.....
Hashcode of Object s1: 366712642
Hashcode of Object s2: 366712642
Hashcode of Object s3: 366712642

As shown from the output, this way of creating Singleton instance doesn’t violates Singleton Principle.

Enum Singleton

Joshua Bloch suggests the use of Enum to implement Singleton design pattern in Java as Java ensures that any enum value is instantiated only once in a Java program. Since Java Enum values are globally accessible, so is the singleton. The drawback is that the enum type is somewhat inflexible; for example, it does not allow lazy initialization.Enum Singleton

package com.dev.dp.creational.singleton;

public enum EnumSingleton {

	INSTANCE;
	
	public static void doMorething() {
		//do More thing
	}
}

Enum Singleton doesn’t violate principle of Singleton in any case described above.

Summary of Singleton Design Pattern with all Scenarios

Finally we learned all about “Singleton Design Pattern in Java with all Scenarios” in a detailed manner. Specifically we have touched almost all the ways to create Singleton object in this article. If we find any more ways, we will update the article in future accordingly. Further if you find any other way or any improvement on the whole article, please feel free to comment or send the email for our review & update.

If you are interested to learn other Design Patterns of GoF, kindly visit article on Java Design Patterns Book.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s