Author Avatar

Pradeep Mishra

0

Share post:

The singleton design pattern is used to restrict the instantiation of a class and ensures that only one instance of the class exists in the JVM. In other words, a singleton class is a class that can have only one object (an instance of the class) at a time per JVM instance. There are various ways to design/code a singleton class.

Class-Based Singleton

The most popular approach is to implement a Singleton by creating a regular class and making sure it has:

  • A private constructor
  • A static field containing its only instance
  • A static factory method for obtaining the instance

Class-level Member (Eager Initialization Method)

Make a private constant static instance (class-member) of this Singleton class.

public class SingletonClass {
    private static final SingletonClass SINGLE_INSTANCE = new SingletonClass();
    private SingletonClass() {}
    public static SingletonClass getInstance() {
        return SINGLE_INSTANCE;
    }
}

Class-level Member (Lazy Initialization Method)

Make a private static instance (class-member) of this singleton class. But, DO NOT instantiate it.
Write a static/factory method that checks the static instance member for null and creates the instance. At last, it returns an object of the singleton class.

public class SingletonClass {
    private static SingletonClass SINGLE_INSTANCE = null;
    private SingletonClass() {}
    public static SingletonClass getInstance() {
        if (SINGLE_INSTANCE == null) {
            synchronized(SingletonClass.class) {
                SINGLE_INSTANCE = new SingletonClass();
            }
        }
        return SINGLE_INSTANCE;
    }
}

Class-level Member (Lazy Initialization with double lock Method)

Here, we run into a problem. Suppose that there are two threads running. Both can get inside of the if statement concurrently when the instance is null. Then, one thread enters the synchronized block to initialize the instance, while the other is blocked. When the first thread exits in the synchronized block, the waiting thread enters and creates another singleton object. Note that when the second thread enters the synchronized block, it does not check to see if the instance is non-null.

public class SingletonClass {
    private static SingletonClass SINGLE_INSTANCE = null;
    private SingletonClass() {}
    public static SingletonClass getInstance() {
        if (SINGLE_INSTANCE == null) {
            synchronized (SingletonClass.class) {
                if (SINGLE_INSTANCE == null) {
                    SINGLE_INSTANCE = new SingletonClass();
                }
            }
        }
        return SINGLE_INSTANCE;
    }
}

By using nested Inner class (Lazy Load method)

  • In this method is based on the Java Language Specifications (JLS). Java Virtual Machine loads static data-members only on-demand. So, here the class SingletonClass loads at first by the JVM. Since there is no static data memberin the class; SingletonClassHolder does not loads or creates SINGLE_INSTANCE.
  • This will happen only when we invoke getIntance method. JLS guaranteed the sequential execution of the class initialization; that means thread-safe. So, we actually do not need to provide explicit synchronization on static getInstance() method for loading and initialization. Here, since the initialization creates the static variable SINGLE_INSTANCE in a sequential way, all concurrent invocations of the getInstance() will return the same correctly initialized SINGLE_INSTANCE without synchronization overhead.
public class SingletonClass {
    private SingletonClass() {}
    private static class SingletonClassHolder {
        static final Something SINGLE_INSTANCE = new SingletonClass();
    }
    public static SingletonClass getInstance() {
        return SingletonClassHolder.SINGLE_INSTANCE;
    }
}

Enum Singleton

All of the above approaches are not full-proof in all the cases. We can still create multiple instances of the above implementations by using serialization or reflection. In both of the cases, we can bypass the private constructor and, hence, can easily create multiple instances. So, the new approach is to create a singleton class by using enums since enums fields are compiled time constants, but they are instances of their enum type. And, they’re constructed when the enum type is referenced for the first time.

public enum EnumSingleton {

    INSTANCE("Initial class info");
    private String info;

    private EnumSingleton(String info) {
        this.info = info;
    }
    public EnumSingleton getInstance() {
        return INSTANCE;
    }
    // getters and setters
}

This approach has serialization and thread-safety guaranteed by the enum implementation itself, which ensures internally that only the single instance is available, correcting the problems pointed out in the class-based implementation.

Singleton is a deceptively simple design pattern, and there are a few common mistakes that a programmer might commit when creating a singleton.

We distinguish two types of issues with singletons:

  • existential (do we need a singleton?)
  • implementational (do we implement it properly?)

I hope you have enjoyed this post and it helped you to understand Singleton Design Pattern in Java. Please like and share and feel free to comment if you have any suggestions or feedback.

Apache Hive 3 Changes in CDP Upgrade: Part-2

In software engineering, a design pattern is a general repeatable solution to a commonly occurring problem in software design. A design pattern isn’t a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations.


Continue Reading

Leave a Reply