Why does the double-checked locking singleton need volatile? — Cracked Java
// Concurrency & Multithreading · Java Memory Model, volatile & happens-before
SeniorTheoryTrickBig TechGoogleAmazon

Why does the double-checked locking singleton need volatile?

Double-checked locking needs volatile on the instance field because object construction is not atomic and its steps can be reordered. Without volatile, another thread can see a non-null reference to a partially constructed object whose fields are still at their default values.

The pattern

class Singleton {
    private static volatile Singleton instance;   // volatile is mandatory

    static Singleton get() {
        Singleton local = instance;               // 1st check (no lock)
        if (local == null) {
            synchronized (Singleton.class) {
                local = instance;
                if (local == null) {              // 2nd check (locked)
                    local = new Singleton();
                    instance = local;
                }
            }
        }
        return local;
    }
}

The point of the pattern is to avoid taking the lock on every read once the singleton exists — the first check is lock-free.

Why volatile is required

instance = new Singleton() is not one operation. It is roughly three:

Program-order intent:        Legal reordering without volatile:
1. allocate memory            1. allocate memory
2. run constructor            3. publish reference  <-- moved up!
3. instance = ref             2. run constructor    <-- runs later
What new Singleton() compiles to (and the illegal reorder)

The JMM permits step 3 (publishing the reference) to be reordered before step 2 (running the constructor), because within the constructing thread there's no observable difference. But a second thread doing the first check (outside the lock) can now read a non-null instance that points at an object whose fields are still zero/null — and use it. That's a corrupted read of a "constructed" object.

Marking instance volatile forbids that reorder: the volatile write of the reference acts as a release, so the constructor's writes happen-before the publication, and the lock-free read acts as an acquire that sees them.

Mark your status