This post will discuss how to implement singleton pattern in Java.

A singleton is simply a class that is instantiated exactly once. Singletons typically represent an intrinsically unique system component, such as the window manager or file system. There are several options to implement the singleton pattern in Java, which are discussed below:

1. Using Eager loading

Eager loading ensures that only one instance of the class is created at the time of class loading. This can be done by declaring a private static final variable of the same class and assigning it a new instance of the class. The constructor of the class must be private to prevent other classes from instantiating it. The class must also provide a public static method that returns the instance of the class. To illustrate, consider the following example where we implement a singleton pattern by keeping the constructor private and exporting a public static factory method that provides access to the sole instance.

Download  Run Code

 
Here, all calls to the getInstance() method returns the same object reference, and no other class instance will ever be created due to the lack of a public or protected constructor. The private constructor is called only once to initialize the private static final field INSTANCE.

2. Using Lazy loading

In eager loading, the private constructor is called only once to initialize the private static final field INSTANCE. We can also initialize the singleton class inside the getInstance() method. This is called lazy loading. Now when the getInstance() method is called the first time, we create an instance of a singleton class by calling its private constructor. From the second time onward, it returns the same object reference. Since a privileged client can invoke the private constructor reflectively with the help of the AccessibleObject.setAccessible() method, we should modify the constructor to throw an exception if it’s asked to create a second instance, as shown below:

Download  Run Code

 
The above implementation is not thread-safe. If multiple threads call the getInstance() method simultaneously, each thread sees the INSTANCE member as null, and each thread might end up creating a new singleton instance. To avoid this, we should place our initialization code inside a synchronized block. Also, to make singleton class serializable, it is not sufficient to add implements Serializable to its declaration. To guarantee singleton, we need to declare all instance fields transient and add the readResolve() method to the singleton class. Otherwise, we’ll create a new instance each time a serialized instance is deserialized. Finally, we should also make our singleton class final to restrict someone from extending it.

Download  Run Code

3. Using Enum

This is the recommended approach for implementing singletons that uses an enum type to represent the single instance of the class. In this method, an enum type with one constant value is defined, and any methods or fields that are needed for the singleton are declared in the enum type. The enum type guarantees that only one instance of itself can be created by Java’s enum mechanism.

Download  Run Code

 
This is functionally equivalent to a Singleton class with the public final field. However, unlike the public field approach, an enum is more concise and guarantees against multiple instantiations, even in the face of sophisticated serialization or reflection attacks.

4. Using Holder pattern

We can use an initialization-on-demand holder design pattern, which enables a safe, highly concurrent lazy initialization with good performance. To illustrate, consider the following example. The static inner class responsible for creating the instance on demand because the static fields of an inner class are only initialized when the class is explicitly called. So, the static class LazyHolder is loaded and initialized by the JVM only when the static method getInstance() is invoked on the class Singleton. The initialization phase writes the static variable INSTANCE in a sequential operation, i.e., non-concurrent, all subsequent concurrent invocations of the getInstance() will return the same initialized INSTANCE without incurring any additional synchronization overhead.

Download  Run Code

That’s all about implementating the singleton pattern in Java.

 
Reference: Joshua Bloch: Creating and Destroying Java Objects