Singleton Design Pattern

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 a simple example of the singleton class. Notice that we are defining the constructor as private so that instance creation using the new keyword is not allowed from outside of the class. We have also provided a public method, which returns the instance of the singleton class. Here, we are creating the instance upon invocation of the getSingletonInstance() method. Hence we call it 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 the main method, we are creating two singleton class reference variables and comparing them if the created instances are the 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

The 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 the 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

The above example, where declaring method synchronized adds performance overhead, as the whole method is synchronized. To avoid this, we can also initialize the instance in the declaration time as shown below. This is called Eager initialization. This provides thread safety, as the 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 the above approach of Eager initialization, an instance is created even before calling for the getSingletonInstance() method is invoked. To avoid this and achieve thread safety, we can have the 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 it returns only one instance every time. In all other above methods, it is possible to get another instance using the reflection method, but using the enumeration method ensures a 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));
	}
}

Conclusion

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