Implement Singleton Pattern in Java
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.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Singleton { // INSTANCE must be static and final to prevent later modification private static final Singleton INSTANCE = new Singleton(); // constructor must be private to prevent another class instance private Singleton() { System.out.println("Constructor called"); } // public static method that returns the same reference every time it is called public static Singleton getInstance() { return INSTANCE; } } public class Main { public static void main(String[] args) { // Constructor is called only once Singleton obj1 = Singleton.getInstance(); Singleton obj2 = Singleton.getInstance(); } } |
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:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
class Singleton { // INSTANCE must be static and not initialized private static Singleton INSTANCE; // The constructor must be private to prevent another class instance private Singleton() { if (INSTANCE != null) { throw new IllegalStateException(); } System.out.println("Constructor called"); } // The public static method returns the same object reference // every time it is called public static Singleton getInstance() { // if the instance is null, create a new instance of the class if (INSTANCE == null) { INSTANCE = new Singleton(); } // return the instance return INSTANCE; } } public class Main { public static void main(String[] args) { // Constructor is called only once Singleton obj1 = Singleton.getInstance(); Singleton obj2 = Singleton.getInstance(); } } |
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.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
final class Singleton implements Serializable { @Serial private static final long serialVersionUID = 1L; private static Singleton INSTANCE; // readResolve method to preserve singleton property @Serial private Object readResolve() { // Return the one true singleton and let the garbage collector // take care of the singleton impersonator return INSTANCE; } public static Singleton getInstance() { synchronized (Singleton.class) { if (INSTANCE == null) { INSTANCE = new Singleton(); } } return INSTANCE; } // … } |
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.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
enum SingletonClass { // the singleton instance INSTANCE; SingletonClass() { System.out.println("Enum constructor called"); } // any other fields or methods of enum // … } public class Main { public static void main(String[] args) { // Enum constructor is called only once SingletonClass obj1 = SingletonClass.INSTANCE; SingletonClass obj2 = SingletonClass.INSTANCE; } } |
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.
|
1 2 3 4 |
class Singleton { public static final Singleton INSTANCE = new Singleton(); private Singleton() {} } |
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.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class Singleton { // constructor must be private to prevent another class instance private Singleton() { System.out.println("Constructor called"); } // private static inner class private static class LazyHolder { // public static final variable holding the instance of the outer class public static final Singleton INSTANCE = new Singleton(); } // public static method that returns the same object reference every time public static Singleton getInstance() { // return the object reference held by LazyHolder class return LazyHolder.INSTANCE; } } public class Main { public static void main(String[] args) { // Constructor is called only once Singleton obj1 = Singleton.getInstance(); Singleton obj2 = Singleton.getInstance(); } } |
That’s all about implementating the singleton pattern in Java.
Reference: Joshua Bloch: Creating and Destroying Java Objects
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)