Wednesday, 22 February 2017

Implementing the Singleton Design Pattern in Java

The Singleton design pattern is one of the most popular design patterns in use. The Singleton design pattern is one of the Gang of Four's (GOF) design patterns and belongs to the Creational Design Pattern category. This article presents a discussion on the Singleton design pattern, its benefits and how it can be implemented in Java.

What is the Singleton Design Pattern?

The Singleton design pattern is used to restrict instances of a class to just one instance. This design pattern states that there can be one — and only one — instance of a class throughout the application's lifecycle. Essentially, a singleton class is one that can have just one instance throughout the application's life cycle and provides a global point of access to it.

Creating a Singleton Class in Java

To implement a singleton class in Java, here's the list of the things you should do:
  1. Create a class that contains a private constructor to restrict instantiation of the class via external sources.
  2. Provide a private, static object of this class which will serve as the only instance.
  3. Create a public, static method in the singleton class that would be used to return the instance when requested.
  4. Write necessary code for thread safety.
Implementing a Singleton Class in Java

Let's dig into some code now. In this section, we will implement a singleton class using Java.

The following code snippet illustrates how you can create a singleton class in Java. This example takes advantage of a static block to create the instance of the singleton class. You also have a static method to retrieve the singleton instance, i.e., get access to the singleton class instance.

package DevX;

public class DemoSingleton {

    private static DemoSingleton instance;
 
    private DemoSingleton(){}
 
    static
    {
        try
        {
            instance = new DemoSingleton();
        }
        catch(Exception e)
        {
            throw new RuntimeException("Exception occured when creating instance" + e.getMessage());
        }
    }
    public static DemoSingleton getInstance(){
        return instance;
    }
}

Note that if you create a singleton class instance using this approach, it's similar to eager initialization since the singleton class instance would be created even before the instance is used. What if you are to create a singleton class instance only when it is needed, i.e., initialize the instance lazily? The following code listing illustrates how you can achieve lazy initialization when implementing the Singleton design pattern in Java.

package DevX;
public class DemoSingleton {
private static DemoSingleton instance;
 private DemoSingleton(){}
    public static DemoSingleton getInstance(){
        if(instance == null) //Check if the singleton instance is null
        {
            instance = new DemoSingleton();
        }
        return instance; //Return the singleton instance
    }
}

Refer to the code listing given above. Note how the singleton instance has been created after checking if the instance is null. In other words, the singleton instance is only created if it is not null — if the instance has not been created yet. But what if multiple threads are accessing the getInstance method? What about thread safety? This is what we will be implemented in the next code listing. The code snippet given below illustrates how you can make the getInstance method thread safe.

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

Note the usage of the "synchronized" keyword in the code snippet above. The Java Programming Language provides excellent support for thread creation and management. The latest versions of the language provides seamless handling of thread safety and concurrency issues.

Here's the complete thread safe version of the singleton class for your reference.

package DevX;
public class DemoSingleton {
private static DemoSingleton instance;
 private DemoSingleton(){}
    public static synchronized DemoSingleton getInstance(){
        if(instance == null){
            instance = new DemoSingleton();
        }
        return instance;
    }
}