Singleton Pattern - Java - Explained

Singleton Pattern - Java - Explained

Intent

The singleton pattern ensures a class has only one instance, and it provides a global point of access to it.

It's a type of creational design pattern

Motivation behind the pattern, the problem it solves?

There has been multiple scenarios where it's expected to have only one instance of the class.
Example: As we have only one printer to serve a group of 10 people we expect everyone comes to that printer to get desired prints right, we share the printer instead purchase different printer for each employee.
In the same way, assume each of these 10 people has their computers and we want to provide a mechanism so that they can just click prints from their systems themselves. Here as we have only one printer we need only one instance which must be shared by all the users.

Singleton pattern is a convention for ensuring only one instance of a class is created .

Singleton pattern approaches

1) Non-thread safe singleton pattern

2) Threadsafe singleton pattern

3) eager instantiation singleton pattern .

github code link

1) Non-thread safe singleton pattern .

This example is mentioned here to understand core implementation of singleton pattern, This is not thread-safe , most of the java applications must support multithreading.

Code Example :

public class NonThreadSafeSingleton {
    private static NonThreadSafeSingleton uniqueInstance;

    private NonThreadSafeSingleton() {
    }

    public static NonThreadSafeSingleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new NonThreadSafeSingleton();
        }
        return uniqueInstance;
    }

    // other useful methods here
    public String getDescription() {
        return "I'm a classic non thread- safe Singleton!";
    }
}

****
public class NonThreasSafeSingletonMain {
    public static void main(String[] args) {
        NonThreadSafeSingleton nonThreadSafeSingleton = NonThreadSafeSingleton.getInstance();
        System.out.println(nonThreadSafeSingleton.getDescription());
    }
}


*** Output 
I'm a classic non thread-safe Singleton!

2) Threadsafe singleton pattern ( double - checked locking)

This is efficient implementation that supports multithreaded scenarios as well.

Code Example :

public class DoubleCheckedLockingSingleton {

    private volatile static DoubleCheckedLockingSingleton uniqueInstance;

    private DoubleCheckedLockingSingleton() {
    }

    public static DoubleCheckedLockingSingleton getInstance() {
        if (uniqueInstance == null) {
            synchronized (DoubleCheckedLockingSingleton.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new DoubleCheckedLockingSingleton();
                }
            }
        }
        return uniqueInstance;
    }

    // other useful methods here
    public String getDescription() {
        return "I'm a double checked locking thread - safe Singleton!";
    }
}

***
public class DoubleCheckedLockingSingletonMain {
    public static void main(String[] args) {
        DoubleCheckedLockingSingleton singleton = DoubleCheckedLockingSingleton.getInstance();
        System.out.println(singleton.getDescription());
    }
}

You may notice using volatile keyword , using this ensures that multiple threads handles the unique instance of singleton instance variable correctly.

Volatile keyword is only can be applied to an instance variable, Once an instance variable is marked as a volatile, it's value is always written to the “Main Memory”.
Each thread has it's own cache in java, volatile variables will not be stored in the thread cache.

3) eager instantiation singleton pattern .

Above two examples were lazy instantiation of singleton pattern. But if we are sure that the singleton object which we are creating is definitely going to be instantiated then eager instantiation singleton pattern is a simple and effective solution which is also a thread-safe solution.

Code Example :

public class EagerInstantiationSingleton {

    private static EagerInstantiationSingleton uniqueInstance = new EagerInstantiationSingleton();

    private EagerInstantiationSingleton() {
    }

    public static EagerInstantiationSingleton getInstance() {
        return uniqueInstance;
    }

    // other useful methods here
    public String getDescription() {
        return "I'm a eagerly instantiated Singleton! using static instance variable.";
    }
}

***
public class EagerInstantiationSingletonMain {
    public static void main(String[] args) {
        EagerInstantiationSingleton singleton = EagerInstantiationSingleton.getInstance();
        System.out.println(singleton.getDescription());
    }
}

Structure

image.png

Applicability

  1. Use this when you want only single instance of a class throughout application .
  2. Good alternative to global variables .

Pros and Cons

Pros

We get only one instance of a class which can be access using one single public method.

Cons

  1. Needs special treatment in multithreaded environment.

Relation with other patterns

1 . A Facade class can be converted to Singleton , as only one instance is needed to access entire facade of services.

  1. Abstract Factories, Builders and Prototypes can be implemented using Singleton.