Mastering Thread‑Safe Singleton in Java: Double‑Check, Static Holder, Enum & Reflection Hacks
Explore multiple Java singleton implementations—including a thread‑safe double‑checked locking version, a static inner‑class approach, an enum‑based solution, and a reflection‑based attack—while learning their key technical details, advantages, pitfalls, and how to protect against serialization and reflection vulnerabilities.
Thread‑Safe Lazy Singleton (Double‑Check Locking)
This implementation uses a volatile static instance field combined with a synchronized block and double‑checked locking to ensure that only one instance is created even under concurrent access.
public class Singleton {
private Singleton() {}
private volatile static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}Key technical points:
Uses double‑check locking to avoid repeated initialization.
Applies the volatile modifier to prevent instruction reordering.
Static Inner‑Class Singleton
This approach leverages the class‑loader mechanism: the inner static class is not loaded until Singleton.getInstance() is called, providing lazy initialization without explicit synchronization.
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}Important notes:
The LazyHolder class is inaccessible from outside, ensuring the instance is created only when needed.
Instance creation occurs when the inner class is loaded, exploiting the class‑loader's lazy loading and guaranteeing thread safety.
Breaking Singleton with Reflection
Reflection can bypass the private constructor, allowing multiple instances to be created. The process consists of three steps:
Obtain the singleton class's constructor via Class.getDeclaredConstructor().
Set the constructor accessible with setAccessible(true).
Instantiate objects using newInstance() and compare them.
// Obtain constructor
Constructor con = Singleton.class.getDeclaredConstructor();
// Make it accessible
con.setAccessible(true);
// Create two instances
Singleton s1 = (Singleton) con.newInstance();
Singleton s2 = (Singleton) con.newInstance();
// Verify they are different
System.out.println(s1.equals(s2)); // prints falseThe output demonstrates that reflection can break the singleton guarantee.
Enum‑Based Singleton
Using an enum provides the simplest and most robust singleton implementation. It inherently prevents multiple instantiation, even against reflection and serialization attacks.
public enum SingletonEnum {
INSTANCE;
}Additional Tips
Enum singletons also guard against deserialization attacks, ensuring the same instance is returned after deserialization.
For other singleton implementations, to maintain a single instance after deserialization, implement a readResolve method that returns the existing instance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Senior Brother's Insights
A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
