Double-checked Locking (DCL) and how to fix it

The term double-checked locking (and sometimes the initials DCL) is used to refer to an infamous programming "pattern" which attempts to avoid synchronization when reading the reference to a singeton instance that is constructed through lazy initialisation (that is, it is not constructed until it is first required). An implemenation using synchronization would be:

public class MyFactory {
  private static MyFactory instance;

  public synchronized static MyFactory getFactory() {
    if (instance == null)
      instance = new MyFactory();
    return instance;
  }
}

The above pattern is perfectly correct. However, some programmers have been reluctant to use it because on all reads it makes a synchronized access and "synchronization is slow". Spurred by this general fear of "slow synchronization", a popular idiom was to attempt to avoid the synchronization on the read as follows:

public class MyBrokenFactory {
  private static MyFactory instance;
  private int field1, field2 ...

  public static MyBrokenFactory getFactory() {
    // This is incorrect: don't do it at home, kids!
    if (instance == null) {
      synchronized (MyBrokenFactory.class) {
        if (instance == null)
          instance = new MyBrokenFactory();
      }
    }
    return instance;
  }

  private MyBrokenFactory() {
    field1 = ...
    field2 = ...
  }
}

On modern JVMs, this optimisation– even if it were correct– is probably no longer that useful. Unfortunately, it's also incorrect. We can show it's incorrect by considering what might happen by two threads that are concurrently calling MyBrokenFactory.getFactory():

Thread 1: 'gets in first' and starts creating instance.

Thread 2: gets in just as Thread 1 has written the object reference to memory, but before it has written all the fields.

1. Is instance null? Yes.
2. Synchronize on class.
3. Memory is allocated for instance.
4. Pointer to memory saved into instance.





7. Values for field1 and field2 are written
to memory allocated for object.




5. Is instance null? No.
6. instance is non-null, but field1 and
field2 haven't yet been set! 
This thread sees invalid values
for field1 and field2!


How to fix double-checked locking?

So how do we fix the double-checked locking "antipattern"? On the next page, we look at options for fixing double-checked locking.