# Double-Checked Locking A design pattern that reduces lock overhead by testing the locking criterion without acquiring the lock first. Most commonly used for thread-safe lazy initialization (Singleton pattern). ## The Problem Naive thread-safe lazy initialization acquires a lock every time: ```java // Correct but slow — lock acquired on every call class Singleton { private static Singleton instance; public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } ``` ## The Solution ```java class Singleton { private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { // First check (no lock) synchronized (Singleton.class) { if (instance == null) { // Second check (with lock) instance = new Singleton(); } } } return instance; } } ``` 1. **First check** — if instance exists, return immediately without locking 2. **Acquire lock** — only if first check fails 3. **Second check** — another thread may have created the instance between check and lock ## Why `volatile` Is Critical Without `volatile`, double-checked locking is **broken** in Java (prior to Java 5). The JVM may reorder `instance = new Singleton()` as: 1. Allocate memory 2. Assign reference to `instance` (now non-null!) 3. Call constructor Another thread could see a non-null `instance` that hasn't been fully constructed. `volatile` prevents this reordering. ## In Other Languages **C++11 (preferred — magic statics):** ```cpp // Thread-safe by the standard Singleton& getInstance() { static Singleton instance; return instance; } ``` **Python** — not typically needed because of the GIL. ## Alternatives - **[[Initialization-on-demand Holder Idiom]]** (Java) — uses class loading guarantees; generally preferred - **`enum` Singleton** (Java) — inherently thread-safe and serializable - **`std::call_once`** (C++) — standard library one-time initialization --- See also: [[Compare-and-Swap]], [[Initialization-on-demand Holder Idiom]]