How to construct a singleton class in a multi-threaded environment in Java

In this article, we will discuss how to create or construct a singleton class in a multi-threaded environment

This is one of the top interview questions for experienced Java developers. We will list down series of questions before delving into details,

  • Do you know Singleton design pattern?
  • Write code for Singleton design pattern?
  • But this is poorly written code, can you write some improved or performance oriented code ?
  • How will you handle singleton design pattern in a multi-threaded environment?
  • Explain Double-Checked Locking pattern?

 

Singleton design pattern:

Singleton design pattern is the

  • solution proposed to return same instance every time
  • restrict instantiation of a class more than once
  • exactly one copy is available at any given point of time
  • ensures only one instance is available in a Java Virtual Machine

Before moving ahead, we need to understand how can we test that every instance returned by the singleton class is always same?

Answer, always check hash code of the returned instance. If it is,

  1. Same –> Then both instances are same and it is singleton
  2. Different –> Both are different instances and there is something wrong with program logic

 

First program for Singleton design pattern:

Basic steps to create Singleton class

Step 1: private static variable of the INSTANCE of the same class (this is only time instance of this class get created)
Step 2: Provide private constructor to restrict instatiation from outside class
Step 3: Provide public static getInstance() method returning same INSTANCE every time

Note: These are steps for eager initialization

SingletonDesignPatternWithEagerInitialization.java

package in.bench.resources.singleton.design.pattern;

public class SingletonDesignPatternWithEagerInitialization {

	// Step 1: private static variable of INSTANCE variable
	private static SingletonDesignPatternWithEagerInitialization INSTANCE = 
			new SingletonDesignPatternWithEagerInitialization();

	// Step 2: private constructor
	private SingletonDesignPatternWithEagerInitialization() {

	}

	// Step 3: Provide public static getInstance() method returning same INSTANCE same time
	public static SingletonDesignPatternWithEagerInitialization getInstance() {
		return INSTANCE;
	}
}

 

The above written code is very poor in terms of performance because program returns singleton instance eagerly i.e.; it instantiates and keep the instance ready to be available even before asking to return

 

Lazy Initialization:

We can actually write more improved version of above code with Lazy initialization

Basic steps to create Singleton class using Lazy Initialization

Step 1: Just declare private static variable of the same class (beware don’t instantiate)
Step 2: Provide private constructor to restrict instatiation from outside class
Step 3: Provide public static getInstance() method  and check

               Step 3.a: If INSTANCE variable is null, then only instantiate
               Step 3.b: Otherwise, return already instantiated INSTANCE variable

Note: These are steps for lazy initialization

Let us move on,

SingletonDesignPatternWithLazyInitialization.java

package in.bench.resources.singleton.design.pattern;

public class SingletonDesignPatternWithLazyInitialization {

	// Step 1: private static variable of INSTANCE variable
	private static SingletonDesignPatternWithLazyInitialization INSTANCE;

	// Step 2: private constructor
	private SingletonDesignPatternWithLazyInitialization() {

	}

	// Step 3: Provide public static getInstance() method returning INSTANCE after checking
	public static SingletonDesignPatternWithLazyInitialization getInstance() {

		if(null == INSTANCE){
			INSTANCE = new SingletonDesignPatternWithLazyInitialization();
		}
		return INSTANCE;
	}
}

 

Singleton design pattern in a multi-threaded environment

Although, we have done performance optimization for singleton design pattern with lazy initialization but still there are certain problems

So, before we start coding the singleton class in a multi-threaded environment we should understand the problem with lazy initialization first

In the above example for Lazy Initialization, suppose 2 or more threads execute in parallell or concurrent, then there may be a issue with multiple instances being instantiated

Let us understand in steps:

  • Thread-1 got the chance and it is put into execution
  • It finds the INSTANCE to be null and therefore Thread-1 instantiates
  • Concurrently if any other thread got the chance and if it tries to executes, then there may be a possibility of new instance is getting created (although it is 50 % chance)
  • Because, new Thread-1 haven’t completed with creation of singleton INSTANCE and another thread at the same time finds singleton INSTANCE to be null and tries to create another one

To overcome this situation, we need to execute lazy instance creation inside synchronized block

 

Basic steps to create Singleton class using Lazy Initialization in a Multi-threaded environment

Step 1: Just declare private static variable of the same class (beware don’t instantiate)
Step 2: Provide private constructor to restrict instantiation from outside class
Step 3: Provide public static getInstance() method  and check
             Step 3.a: If INSTANCE variable is null, then only instantiate
             Step 3.b: Otherwise, return already instantiated INSTANCE variable
Step 4: In addition to above detailed steps, also make INSTANCE variable as volatile. This will help getting latest updated copy every time, as it will read from main memory than in its own CPU-cache area

Note: If your singleton INSTANCE is going to be executed in a single threaded environment, then there is no need of making INSTANCE variable as volatile

 

SingletonDesignPatternInMultiThreadedEnvironment.java

package in.bench.resources.singleton.design.pattern;

public class SingletonDesignPatternInMultiThreadedEnvironment {

	// Step 1: private static variable of INSTANCE variable
	private static volatile SingletonDesignPatternInMultiThreadedEnvironment INSTANCE;

	// Step 2: private constructor
	private SingletonDesignPatternInMultiThreadedEnvironment() {

	}

	// Step 3: Provide public static getInstance() method returning INSTANCE after checking
	public static SingletonDesignPatternInMultiThreadedEnvironment getInstance() {

		// synchronized block
		synchronized (SingletonDesignPatternInMultiThreadedEnvironment.class) {
			if(null == INSTANCE){
				INSTANCE = new SingletonDesignPatternInMultiThreadedEnvironment();
			}
			return INSTANCE;
		}
	}
}

This way, we can assure that every time single & same instance is returned

 

Performance issue with above approach:

But again, there is a performance issue with above program. Let us understand,

  • Assume that ONE instance is created and available for use (i.e.; singleton instance)
  • And with this single & same instance, some thread (Thread-Arya) is executing in a multi-threaded environment
  • Now suppose a new thread (Thread-Surya) got the execution cycle and trying to get the singleton instance, although it is already created & available for use
  • But Thread-Surya has to wait till Thread-Arya releases the lock or comes out of synchronized block
  • This is bad and poor situation, reason being singleton instance is already created and still it has to wait to get that instance
  • Ideally speaking, Thread-Surya doesn’t need to wait for Thread-Arya to release lock and then check the condition and then proceed with its execution

To conclude, we need to design singleton pattern in a such a way that

  • once if singleton instance is created & available for use
  • then no threads need to wait
  • rather it should to get singleton instance and continue with its execution

 

To design such pattern, we need to look into double-checked locking design pattern

Let us move on and see exactly Double-Checked Locking Pattern in details

SingletonDesignPatternWithDCL.java

package in.bench.resources.singleton.design.pattern;

public class SingletonDesignPatternWithDCL {

	// Step 1: private static variable of INSTANCE variable
	private static volatile SingletonDesignPatternWithDCL INSTANCE;

	// Step 2: private constructor
	private SingletonDesignPatternWithDCL() {

	}

	// Step 3: Provide public static getInstance() method returning INSTANCE after checking
	public static SingletonDesignPatternWithDCL getInstance() {

		// double-checking lock
		if(null == INSTANCE){

			// synchronized block
			synchronized (SingletonDesignPatternWithDCL.class) {
				if(null == INSTANCE){
					INSTANCE = new SingletonDesignPatternWithDCL();
				}
			}
		}
		return INSTANCE;
	}
}

 

Conclusion:

We have covered almost for every possible situation that may arise problem while dealing with Singleton design pattern; like

  • Eager initialization
  • Lazy initialization
  • Lazy initializtion in a multi-threaded environment
  • Double checking lock desing pattern

It is a design choice to choose from above listed approaches to begin with, as starting with double-checking lock in a non-threaded environment yields poor results

So, it is always design choice to look that which approach fits the case perfectly for the required business requirement

 

References:

http://www.benchresources.net/singleton-design-pattern-with-java-serialization/
https://blogs.oracle.com/JavaFundamentals/entry/using_enhanced_for_loops_with
http://www.oracle.com/technetwork/articles/java/singleton-1577166.html
http://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking–clever–but-broken.html

 

Read Also:

 

Happy Coding !!
Happy Learning !!

How to serialize and de-serialize ArrayList in Java
How to stop Serialization in Java