Java — Singleton Design Pattern Example | Code Factory
Donate : Link
WordPress Blog : Link
Singleton design pattern is used when you want to have only one instance of a given class.
It is a creational design pattern wherein we deal with the creation of objects.
In object-oriented design, It’s very important for some classes to have only one instance. That’s because they represent something unique, something that’s one of its kind.
How do you ensure that a class has only one instance? Well, there are several ways of doing this in Java. But all of them are based on the following basic ideas:
- Declare a private constructor to prevent others from instantiating the class.
- Create the instance of the class either during class loading in a static field/block, or on-demand in a static method that first checks whether the instance exists or not and creates a new one only if it doesn’t exist.
Let’s see all the possible solutions with code samples one by one :
1. Eagerly Initialized Singleton
package com.example.java.programming.singleton;/**
* @author code.factory
*
*/
public class EagerSingleton { /* private constructor to prevent others from instantiating this class */
private EagerSingleton() {
} /* Create an instance of the class at the time of class loading */
private static final EagerSingleton instance = new EagerSingleton(); /* Provide a global point of access to the instance */
public static EagerSingleton getInstance() {
return instance;
}}
The disadvantage of this approach is that the instance is created irrespective of whether it is accessed or not. This is fine if the object is simple and does not hold any system resources. But can have performance implications if it allocates a large amount of system resources and remains unused.
2. Eagerly Initialized Static Block Singleton
You can also create the one-off instance of the class in a static block. This works because the static block is executed only once at the time of class loading.
The advantage with static block initialization is that you can write your initialization logic or handle exceptions in the static block.
package com.example.java.programming.singleton;/**
* @author code.factory
*
*/
public class EagerStaticBlockSingleton { private static final EagerStaticBlockSingleton instance; /* Don't let anyone else instantiate this class */
private EagerStaticBlockSingleton() {
} /* Create the one-and-only instance in a static block */
static {
try {
instance = new EagerStaticBlockSingleton();
} catch (Exception ex) {
throw ex;
}
} /** Provide a public method to get the instance that we created */
public static EagerStaticBlockSingleton getInstance() {
return instance;
}}
Just like the previous solution, the instance is created whether or not it is needed by the application.
3. Lazily Initialized Singleton
Lazy initialization means delaying the initialization of something until the first time it is needed.
In the following implementation, we first check whether the instance is already created or not in the getInstance()
method. If the instance is already created, we simply return it, otherwise, we first create the instance and then return it:
package com.example.java.programming.singleton;/**
* @author code.factory
*
*/
public class LazySingleton { private static LazySingleton instance; /* Don't let anyone else instantiate this class */
private LazySingleton() {
} /* Lazily create the instance when it is accessed for the first time */
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
Notice the use of synchronized
keyword in the getInstance()
method. This is needed to prevent race conditions in multi-threaded environments.
Let’s say that the instance
is not created yet, and two threads enter the getInstance()
method simultaneously. In that case, the instance==null
check will evaluate to true and both the threads will create a new instance of the class.
The synchronized
keyword ensures that only one thread can execute the getInstance()
method at a time.
4. Lazily Initialized Double-Checked Locking Singleton
The synchronized
keyword added to the getInstance()
method prevents race conditions, but it also incurs some performance penalty.
Following is an optimized version of the lazily initialized singleton where — instead of making the entire method synchronized
, we create a synchronized
block and wrap only the instantiation part inside the synchronized
block
package com.example.java.programming.singleton;/**
* @author code.factory
*
*/
public class LazyDoubleCheckedLockingSingleton {
private static volatile LazyDoubleCheckedLockingSingleton instance; /* private constructor to prevent others from instantiating this class */
private LazyDoubleCheckedLockingSingleton() {
} /* Lazily initialize the singleton in a synchronized block */
public static LazyDoubleCheckedLockingSingleton getInstance() {
if (instance == null) {
synchronized (LazyDoubleCheckedLockingSingleton.class) {
// double-check
if (instance == null) {
instance = new LazyDoubleCheckedLockingSingleton();
}
}
}
return instance;
}
}
The above approach is called Double-Checked Locking because we double-check whether the variable is initialized or not inside the synchronized
block.
The double-checking is very important here. Let’s say that two threads T1
and T2
enter the getInstance()
method simultaneously. The instance==null
check will evaluate to true, so both of them will enter the synchronized
block one-by-one. If the double check was not there, both threads would create a new instance.
Also, notice the use of volatile
keyword with the instance variable. This is necessary to prevent compilers from doing their own optimizations and handle the singleton correctly.
5. Lazily Initialized Inner Class Singleton (Bill Pugh singleton)
Bill Pugh came up with a very efficient solution to create singletons. It is called Initialization-on-demand holder idiom. In this approach, a static inner class is used to lazily create a singleton instance.
package com.example.java.programming.singleton;/**
* @author code.factory
*
*/
public class LazyInnerClassSingleton { /* private constructor to prevent others from instantiating this class */
private LazyInnerClassSingleton() {
} /**
* This inner class is loaded only after getInstance() is called for the first
* time.
*/
private static class SingletonHelper {
private static final LazyInnerClassSingleton INSTANCE = new LazyInnerClassSingleton();
} public static LazyInnerClassSingleton getInstance() {
return SingletonHelper.INSTANCE;
}}
Note that, the inner class is not loaded until the getInstance()
method is invoked for the first time. This solution is thread-safe and doesn’t require any synchronization. It is the most efficient approach among all the singleton design pattern implementations.
6. Enum Singleton
An Enum is singleton by design. All the enum values are initialized only once at the time of class loading.
package com.example.java.programming.singleton;import java.util.Arrays;/**
* An Enum value is initialized only once at the time of class loading. It is
* singleton by design and is also thread-safe.
*/
enum EnumSingleton {
WEEKDAY("Monday", "Tuesday", "Wednesday", "Thursday", "Friday"),
WEEKEND("Saturday", "Sunday"); private String[] days; EnumSingleton(String... days) {
System.out.println("Initializing enum with " + Arrays.toString(days));
this.days = days;
} public String[] getDays() {
return this.days;
} @Override
public String toString() {
return "EnumSingleton{" + "days=" + Arrays.toString(days) + '}';
}
}public class EnumSingletonExample {
public static void main(String[] args) {
System.out.println(EnumSingleton.WEEKDAY);
System.out.println(EnumSingleton.WEEKEND);
}
}
Output :
Initializing enum with [Monday, Tuesday, Wednesday, Thursday, Friday]
Initializing enum with [Saturday, Sunday]
EnumSingleton{days=[Monday, Tuesday, Wednesday, Thursday, Friday]}
EnumSingleton{days=[Saturday, Sunday]}
The disadvantage of this approach is that it is a bit inflexible compared to other approaches.
Singletons and Reflection
Java’s Reflection API is very powerful. You can use Reflection to instantiate a class even if the class’s constructor is private.
package com.example.java.programming.singleton;import java.lang.reflect.Constructor;/**
* @author code.factory
*
*/
public class SingletonAndReflection { public static void main(String[] args) {
MySingleton singletonInstance = MySingleton.getInstance();
MySingleton reflectionInstance = null; try {
Constructor[] constructors = MySingleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
constructor.setAccessible(true);
reflectionInstance = (MySingleton) constructor.newInstance();
}
} catch (Exception ex) {
throw new RuntimeException(ex);
} System.out.println("singletonInstance hashCode: " + singletonInstance.hashCode());
System.out.println("reflectionInstance hashCode: " + reflectionInstance.hashCode());
}}class MySingleton {
private static final MySingleton instance = new MySingleton(); private MySingleton() {
} public static MySingleton getInstance() {
return instance;
}
}
Output :
singletonInstance hashCode: 366712642
reflectionInstance hashCode: 1829164700
Notice how we created a new instance of the Singleton using constructor.newInstance()
. This destroys the singleton pattern.
Protection against Reflection
To protect your singleton class against instantiation via reflection, you can throw an exception from the private constructor if the instance is already created like this
class MySingleton {
private static final MySingleton instance = new MySingleton(); private MySingleton() {
// protect against instantiation via reflection
if(instance != null) {
throw new IllegalStateException("Singleton already initialized");
}
} public static MySingleton getInstance() {
return instance;
}
}
You can also use an Enum singleton to guard against reflection. Enums can’t be initialized via reflection. They are a sure shot way of having a single instance no matter what.
Singletons and Serialization
We often need to serialize/deserialize objects in Java. Any class that needs to be serialized/deserialized must implement the serializable interface.
Note that, the de-serialization step always creates a new instance of the class, which destroys the singleton pattern. Here is an example
package com.example.java.programming.singleton;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;/**
* @author code.factory
*
*/
public class SingletonAndSerialization {
public static void main(String[] args) {
SerializableSingleton instance1 = SerializableSingleton.getInstance(); try {
// Serialize singleton object to a file.
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("singleton.ser"));
out.writeObject(instance1);
out.close(); // Deserialize singleton object from the file
ObjectInput in = new ObjectInputStream(new FileInputStream("singleton.ser"));
SerializableSingleton instance2 = (SerializableSingleton) in.readObject();
in.close(); System.out.println("instance1 hashCode: " + instance1.hashCode());
System.out.println("instance2 hashCode: " + instance2.hashCode());
} catch (IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
}
}class SerializableSingleton implements Serializable {
private static final long serialVersionUID = 1L; private static SerializableSingleton instance; private SerializableSingleton() {
} public static synchronized SerializableSingleton getInstance() {
if (instance == null) {
instance = new SerializableSingleton();
}
return instance;
}
}
Output :
instance1 hashCode: 865113938
instance2 hashCode: 1283928880
Notice how the hashCodes of the original instance and the de-serialized instance are different. There are clearly two instances of our singleton class.
Protection against Serialization
To prevent the de-serialization process from creating a new instance, you can implement the readResolve()
method in the singleton class. It is invoked when the object is de-serialized.
In the readResolve()
method, you must return the existing instance -
package com.example.java.programming.singleton;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;/**
* @author code.factory
*
*/
public class SingletonAndSerialization {
public static void main(String[] args) {
SerializableSingleton instance1 = SerializableSingleton.getInstance(); try {
// Serialize singleton object to a file.
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("singleton.ser"));
out.writeObject(instance1);
out.close(); // Deserialize singleton object from the file
ObjectInput in = new ObjectInputStream(new FileInputStream("singleton.ser"));
SerializableSingleton instance2 = (SerializableSingleton) in.readObject();
in.close(); System.out.println("instance1 hashCode: " + instance1.hashCode());
System.out.println("instance2 hashCode: " + instance2.hashCode());
} catch (IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
}
}class SerializableSingleton implements Serializable {
private static final long serialVersionUID = 1L; private static SerializableSingleton instance; private SerializableSingleton() {
} public static synchronized SerializableSingleton getInstance() {
if (instance == null) {
instance = new SerializableSingleton();
}
return instance;
} // implement readResolve method to return the existing instance
protected Object readResolve() {
return instance;
}
}
Output :
instance1 hashCode: 865113938
instance2 hashCode: 865113938