Singleton Class in Java | Creational Design Pattern
Published on August 19, 2024
To implement a thread-safe Singleton using the Bill Pugh Singleton Design while also making it cloneable-proof, serializable-proof, and reflection-proof, you can combine several techniques into a single implementation. Here's how you can achieve this:
1. Bill Pugh Singleton Design (Static Inner Class): This ensures thread-safe and lazy initialization of the Singleton instance.
2. Prevent Cloning: Override the clone()
method and throw a CloneNotSupportedException
.
3. Prevent Serialization: Implement the readResolve()
method to return the existing Singleton instance.
4. Prevent Reflection: Throw an exception in the constructor if an instance already exists.
Here's the complete implementation:
import java.io.Serializable;
public class Singleton implements Cloneable, Serializable {
// Private constructor prevents instantiation from other classes
private Singleton() {
// Preventing instantiation via reflection
if (SingletonHelper.INSTANCE != null) {
throw new RuntimeException("Use getInstance() method to create");
}
}
// Static inner class responsible for holding the Singleton instance
private static class SingletonHelper {
// The instance is created when the SingletonHelper class is loaded
private static final Singleton INSTANCE = new Singleton();
}
// Global access point for the Singleton instance
public static Singleton getInstance() {
return SingletonHelper.INSTANCE;
}
// Prevent cloning of the Singleton instance
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Cloning of this Singleton is not allowed");
}
// Ensure that during deserialization, the same instance is returned
protected Object readResolve() {
return getInstance();
}
}
Key Components
-
Static Inner Class (SingletonHelper)
- This is the Bill Pugh approach. The
INSTANCE
is created only when theSingletonHelper
class is loaded into memory. This ensures lazy initialization and thread safety without needing synchronization.
- This is the Bill Pugh approach. The
-
Private Constructor
- The private constructor prevents direct instantiation from other classes.
- It also checks if the instance already exists (to prevent creation via reflection).
-
Clone Prevention
- The
clone()
method is overridden to throw aCloneNotSupportedException
, preventing the Singleton instance from being cloned.
- The
-
Serialization Prevention
- The
readResolve()
method ensures that during deserialization, the existing Singleton instance is returned instead of creating a new one.
- The
-
Reflection Prevention
- The constructor checks if the instance already exists, and if so, it throws an exception to prevent creation via reflection.
How This Works
- Thread Safety: The Bill Pugh approach ensures thread safety via the static inner class, which is loaded only when needed.
- Cloning: Attempting to clone the Singleton instance will throw an exception, preserving the Singleton property.
- Serialization: Deserializing the Singleton will not create a new instance; instead, it will return the existing instance.
- Reflection: Even if someone tries to break the Singleton using reflection, the exception in the constructor will prevent multiple instances.
This implementation is robust and ensures that your Singleton class maintains a single instance across various potential pitfalls.