Singleton design pattern is a creational design pattern. It is part of GoF design patterns. Singleton design pattern definition says that a singleton class can have only one instance variable.

GoF Definition : Ensure a class only has one instance, and provide a global point of access to it.

  • Singleton design pattern says that only one instance of a particular class can exist if it is said to be singleton class.
  • Class should provide a global access method to get the singleton instance.

How to make a class singleton

  • Declare the class constructor as private.
  • Provide a method, which returns instance of the class.
  • Make sure to check if instance is already not present. If instance is already present, return that existing instance.
  • If instance is not present, then create an instance and return it.

Lazy Initialization

Following is the simple example of singleton class. Notice that we have made constructor private, so that instance creation using new keyword is prevented from outside of the class. We have also provided a public method, which returns instance of singleton class. Here, we are creating instance upon invocation of getSingletonInstance() method. Hence it is called Lazy initialization.

package com.asb.singleton;

public class Singleton {
	
	private static Singleton instance; 
	
	//private constructor
	private Singleton(){
	}
	
	//Public accessor method to get instance
	public static Singleton getSingletonInstance(){
		
		//Lazy initialization
		if(null == instance) 
		{
			System.out.println("Creating new instance");
			instance = new Singleton();
		}
		else
		{
			System.out.println("Instance already present \n Returning insatnce");
		}
		return instance;
	}
}

Create a class(SingletonExample.java) to test the Singleton class as shown below. Here, inside main method, we are creating two singleton class reference variables and comparing them if the created instances are same or not.

package com.asb.singleton;

public class SingletonExample {

	public static void main(String args[]){
		
		System.out.println("Singleton Example");
		
		Singleton s1 = Singleton.getSingletonInstance();
		Singleton s2 = Singleton.getSingletonInstance();
		
		System.out.println("Both s1 and s2 are same instances :: "+(s1==s2));
	}
}

Output

Thread safe Lazy initialization Example

Above class is not thread safe. If two threads are accessing simultaneously to get an instance of our Singleton class, it may end up creating two instances of singleton class. To avoid this, we can make our getSingletonInstance() method synchronized as shown below.

package com.asb.singleton;

public class Singleton {
	
	private static Singleton instance; 
	
	//private constructor
	private Singleton(){
	}
	
	//Public accessor method to get instance(Synchronized makes the method thread safe)
	public static synchronized Singleton getSingletonInstance(){
		
		//Lazy initialization
		if(null == instance) 
		{
			System.out.println("Creating new instance");
			instance = new Singleton();
		}
		else
		{
			System.out.println("Instance already present \n Returning insatnce");
		}
		return instance;
	}
}

Eager Initialization

Above example, where declaring method synchronized adds performance overhead, as whole method is synchronized. To avoid this, we can also initialize instance in the declaration time as shown below. This is called Eager initialization. This provides thread safety, as instance is initialized earlier itself.

package com.asb.singleton;

public class SingletonEagerInitialization {
	
	//Eager Initialization:
	private static SingletonEagerInitialization instance = new SingletonEagerInitialization(); 
	
	//private constructor
	private SingletonEagerInitialization(){ }
	
	//Public accessor method to get instance
	public static SingletonEagerInitialization getSingletonInstance() {
		
		System.out.println("Returning insatnce");
		return instance;
	}
}

Bill Pugh Example

In above approach of Eager initialization, an instance is created even before call for getSingletonInstance() method is invoked. To avoid this and achieve thread safety, we can have following implementation, where we are using a static inner helper class, which instantiates singleton class on invocation of getSingletonInstance() method.

package com.asb.singleton;

public class BillPughSingleton {
	
	private BillPughSingleton(){ }
	
	public static BillPughSingleton getSingletonInstance() {
		System.out.println("Returning insatnce");
		return SingletonHelper.instance;
	}
	
	//A static private helper class to create an instance
	private static class SingletonHelper {
		
		private static final BillPughSingleton instance = new BillPughSingleton();
	}
}

Enumeration Example

We can also use Enumeration to implement singleton as shown below. Here, JVM creates the instance and makes sure that only one instance is returned every time. In all other above methods, it is possible to get another instance using reflection method, but using enumeration method ensures guarantee that only one instance exists all the time.

package com.asb.singleton;

public enum SingletonEnum {
	INSTANCE;
}

//Access the singleton instance
package com.asb.singleton;

public class SingletonExample {

	public static void main(String args[]){
		
		System.out.println("Singleton Example");
		
		SingletonEnum s1 = SingletonEnum.INSTANCE;
		SingletonEnum s2 = SingletonEnum.INSTANCE;
		
		System.out.println("Both s1 and s2 are same instances :: "+(s1==s2));
	}
}

In this article, we learned about Singleton class, how to create singleton class using different methods and their advantages and disadvantages.

Also Read