Creational Design Pattern — Singleton Pattern

Singleton Design Pattern in Java?

Everything you must know about Singleton Design Pattern.

Vikram Gupta
Javarevisited

--

Photo by Caspar Camille Rubin on Unsplash

In this article, we will see what the intent of the Singleton design pattern is, what problems it solves, and its applicability.

There are different creational design patterns and they have their intent and applicability.

Creational design patterns provide various object creation mechanisms, which increase flexibility and reuse of existing code: —

  1. Factory Method — The Factory Method is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.
  2. Abstract Factory Method — Abstract Factory is a creational design pattern that lets you produce families of related objects without specifying their concrete classes.
  3. Builder — Builder is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.
  4. Singleton — Singleton is a creational design pattern that lets you ensure that a class has only one instance while providing a global access point to this instance.
  5. Prototype — A prototype is a creational design pattern that lets you copy existing objects without making your code dependent on their classes.

What Is a Singleton Design Pattern?

  1. Singleton design pattern allows us to create only one instance of a class and make sure that there exists only one Object in JVM.
  2. Singleton class must have a public static method to get the instance of the class from anywhere in the application [from different classes, different packages, etc].
  3. Singleton class must have a private constructor to instantiate the object of the class.
  4. Singleton class must have a private static variable of the same class which is the only reference of the class[basically this variable will point to only the Object of the class].
Singleton Design Pattern

There are different implementation methods that lead to one goal which is having a single instance of a class at any given point in time in JVM. Let’s see different implementation approaches for the Singleton design pattern

1. Eager Initialization :

  1. This is the simplest implementation of the singleton design pattern. In this method, the private static variable of the same class (basically a reference variable) is assigned the object of the class at the time of loading the class into the JVM memory.
  2. This type of implementation applies to scenarios when we always want the instance of the class.

Following is a simple program to illustrate the construction of a singleton object using Eager initialization.

package com.vikram;

public class EagerSingleton {
//Only object created when class is loaded and theInstance is private static var pointing to it.
private static EagerSingleton theInstance = new EagerSingleton();

//private constructor
private EagerSingleton(){

}
//public method to return single instance of class .
public static EagerSingleton getInstance(){
return theInstance;
}
}

Advantage :

  • This implementation is very easy to write.

Disadvantages :

  • The object will always be created no matter whether it is required or not and hence there will be a wastage of heap memory in case we don’t need the instance of this singleton class.
  • This approach is difficult for exception handling.

2. Static Block Initialization :

Static block initialization is similar to Eager initialization. In this case, the object is created inside a static block and at the time of class loading into the JVM memory. Now we can have an exception-handling mechanism inside the static block.

Here is an example of static block initialization:

package com.vikram;

public class StaticBlockSingleton {
//private static variable
private static StaticBlockSingleton theInstance = null;

//static block to initialize theInstance variable using constructor call
static {
try{
theInstance = new StaticBlockSingleton();
}catch (Exception exception){
System.out.println("Exception occurred while creating the instance "+exception);
}
}
//private constructor
private StaticBlockSingleton(){

}
//public static method to get this single instance .
public static StaticBlockSingleton getInstance(){
return theInstance;
}
}

Advantage :

  • This implementation is very easy to write and provides a way to handle exceptions inside the static block.

Disadvantages :

  • The object will always be created no matter whether it is required or not and hence there will be a waste of heap memory.

3. Lazy Initialization :

In the case of the lazy initialization approach, the object of the class is created when the getInstance() method is called. Let’s have a look at the code to understand this.

package com.vikram;

public class LazySingleton {

//private static variable of same class
private static LazySingleton theInstance = null;

//private constructor
private LazySingleton(){

}

//public static method to get the singleton object when required
public static LazySingleton getInstance(){
if (theInstance == null){
theInstance = new LazySingleton();
}
return theInstance;
}
}

Advantage :

  • The object is created when it is required by calling the public static method getInstance().
  • An exception-handling mechanism can be achieved.

Disadvantages :

  • In the case of a multi-threading environment, multiple threads can be inside the if block at the same time and they may create multiple objects. So it will violate the rule of the Singleton design pattern.

4. Thread Safe Singleton :

To overcome the disadvantage of lazy initialization we can have a synchronized getInstance() method so that only one thread will be able to enter the method at a time.

package com.vikram;

public class ThreadSafeSingleton {

//private static variable of same class
private static ThreadSafeSingleton theInstance = null;

//private constructor
private ThreadSafeSingleton(){

}

//thread safe public static method to get the singleton object when required
synchronized public static ThreadSafeSingleton getInstance(){
if (theInstance == null){
theInstance = new ThreadSafeSingleton();
}
return theInstance;
}
}

Advantage :

  • This approach guarantees us that only one instance will be created at any given point in time inside the memory. As getInstance() method is now synchronized.
  • Also, with this approach Exception handling mechanism can be achieved.

Disadvantages :

  • As the method is synchronized, only one thread at a time will be able to access the getInstance() method at any given time because there will be only one lock available per object that is shared between the threads. Hence it will reduce performance.

5. Lazy Initialization with Double-Check Locking :

As we have seen in the case of a thread-safe singleton approach it was allowed to create only one instance in a multi-threaded environment but reduced the overall performance. Hence we would use a Synchronized block for thread safety inside if condition and one more check would be required so that only one instance is created by multiple threads.

package com.vikram;

public class DoubleCheckedSingleton {

//private static variable of same class
private static DoubleCheckedSingleton theInstance = null;

//private constructor
private DoubleCheckedSingleton(){

}

//thread safe public static method to get the singleton object when required
public static DoubleCheckedSingleton getInstance(){
if (theInstance == null){
synchronized(DoubleCheckedSingleton.class){
//only one thread will be able to access this block.
if (theInstance == null){
//once the object is created by one thread , for other threads this if condition will be false.
theInstance = new DoubleCheckedSingleton();
}
}
}
return theInstance;
}
}

Advantage :

  • This approach guarantees us that only one instance will be created at any given point in time inside the memory. As the if condition is synchronized, it will be less overhead than the synchronized method.
  • With this approach, the Exception handling mechanism can be achieved.

Disadvantages :

  • Initially, there would be less performance but it would increase once the object is created.

6. Bill Pugh Singleton :

Now we have seen in all the above approaches either the object was created when the class was loaded into JVM memory or there were issues with the multithreaded environment and hence reducing the performance. Bill Pugh instead of using the above approaches implemented his Singleton class using the nested static class.

Before jumping onto the example code, let’s understand what Class loading and Class instantiation means in Java programming.

Classloading :

Whenever the JVM determines it needs a class (eg. to use its static variables, to create a new object, to use its static methods, etc) JVM’s class loader (java.lang.ClassLoader) will load the class, and then static variables are initialized and static blocks are executed. This is a one-time activity done by the class loader.

Examples :

ClassName.staticVariable; //class is loaded into JVM by the class loader

ClassName.staticMethod();//class is loaded into JVM by the class loader

ClassName obj = new ClassName();//class is loaded into JVM by the class loader

As a result of this class loading procedure, static variables are initialized and static blocks are executed.

Examples :

static int var = 10; //this is initialized when class is loaded into JVM.
static {
System.out.println(“static block executed !!!”);//static block executed .
}

Class Instantiation :

When we create an object of a class that means the class is instantiated.

Example :

ClassName obj = new ClassName()//object created , class instantiated

As a result of this class instantiation, the constructor is called and the constructor body is executed.

public ClassName() {

}//this constructor body is executed.

Bill Pugh Singleton's Example Program:

package com.vikram;

public class Singleton {

//private constructor
private Singleton(){

}
/*
inner static class SingletonHelper is loaded when
SingletonHelper.theSingletonInstance is executed/called.
*/
private static class SingletonHelper {
private static final Singleton theSingletonInstance = new Singleton();
}
//public static method to get theSingletonInstance
public static Singleton getInstance(){
return SingletonHelper.theSingletonInstance;
/*
when above line is executed SingletonHelper class is loaded and
then static variable theSingletonInstance is initialized
*/
}
}

Now let’s understand this approach:

When the getInstance() method is called using Singleton.getInstance(), then the Singleton class is loaded into the JVM and then SingletonHelper.theSingletonInstance is executed, then the SingletonHelper class is loaded into JVM and the static variable theSingletonInstance is initialized.

And as we discussed loading of a class is done only once, if already not loaded, hence there will be only one instance of this class.

This approach is widely used and well-followed as it does not use lazy/static/synchronization-related things which we discussed earlier.

That’s all for this article. Hope you liked it.

You Can Follow Vikram Gupta For Similar Content.

--

--

Vikram Gupta
Javarevisited

-: Empowering Developers to Ace Their Technical Interviews :-