Home  Synchronization and concurrency  wait/notify  final  volatile  synchronized keyword  Java threading  Deadlock (and avoiding it)  Java 5: ConcurrentHashMap  Atomic variables  Explicit locks  Queues  Semaphores  CountDownLatch  CyclicBarrier

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.

Article written by Neil Coffey (@BitterCoffey).

Software

 LetterMeister (word puzzle game for iPhone)
 Currency Quoter (currency converter/predictor)
 French Vocab Games for iPhone/iPad
 Vocabularium: create Spanish vocab podcasts


Java programming articles and tutorials on this site are written by Neil Coffey (@BitterCoffey). Suggestions are always welcome if you wish to suggest topics for Java tutorials or programming articles, or if you simply have a programming question that you would like to see answered on this site. Most topics will be considered. But in particular, the site aims to provide tutorials and information on topics that aren't well covered elsewhere, or on Java performance information that is poorly described or understood. Suggestions may be made via the Javamex blog (see the site's front page for details).
Copyright © Neil Coffey 2014. All rights reserved.