Classical Synchronization ProblemsThread-Safe Singleton & Double-Checked LockingMedium⏱️ ~2 min

Better Alternatives to DCL

Key Insight
Double-checked locking is complex and error-prone. Most languages offer simpler, safer alternatives that let the runtime handle thread-safety.

Eager Initialization

Create the instance when the class loads. No lazy initialization, no race condition. The JVM or runtime guarantees thread-safe class loading. Simple and bulletproof.

Trade-off: Instance is created even if never used. Fine for lightweight objects. Wasteful for expensive resources that might not be needed.

Initialization-on-Demand Holder (Java)

A nested static class holds the instance. Java guarantees the inner class is loaded only when first accessed. Lazy, thread-safe, no synchronization needed.

Holder Pattern vs DCL
Holder PatternJVM handles synchronizationZero runtime overheadDouble-Checked LockYou handle synchronizationVolatile read each call

Enum Singleton (Java)

Declare a single-element enum. The JVM guarantees exactly one instance. Handles serialization automatically. Cannot be broken by reflection. Joshua Bloch calls this the best way to implement singleton in Java.

std::call_once (C++)

C++11 provides std::call_once with std::once_flag. The runtime ensures the initialization function runs exactly once, even with concurrent calls. Cleaner than manual DCL.

Static Local Variables (C++11)

C++11 guarantees thread-safe initialization of static local variables. Just return a reference to a static local. The compiler handles all the synchronization.

Recommendation: Use language-provided mechanisms. Holder pattern in Java, static local in C++11, lazy_static in Rust. DCL is a last resort when you truly need control.
💡 Key Takeaways
Eager initialization creates the instance at class load time. Simple and thread-safe, but not lazy.
Holder pattern (Java) uses a nested class. JVM guarantees thread-safe class loading. Lazy with zero synchronization overhead.
Enum singleton (Java) is bulletproof. Single instance guaranteed by JVM. Handles serialization and reflection attacks.
std::call_once (C++) runs initialization exactly once. Cleaner than manual DCL with proper memory ordering built in.
C++11 static local variables are thread-safe. The simplest solution: return a reference to a static local. Compiler handles the rest.
📌 Examples
1Java Holder: class Singleton { private static class Holder { static final Singleton INSTANCE = new Singleton(); } static Singleton getInstance() { return Holder.INSTANCE; } }
2C++11 static local: Singleton& getInstance() { static Singleton instance; return instance; } Thread-safe since C++11.
3Rust lazy_static: lazy_static! { static ref INSTANCE: Singleton = Singleton::new(); } Macro handles all synchronization.
← Back to Thread-Safe Singleton & Double-Checked Locking Overview