Newsletter sign-up
View all newsletters

Sign up for our technology specific newsletters.

Enterprise Java
Email Address:

Double-checked locking: Clever, but broken

Do you know what synchronized <em>really</em> means?

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
From the highly regarded Elements of Java Style to the pages of JavaWorld (see Java Tip 67), many well-meaning Java gurus encourage the use of the double-checked locking (DCL) idiom. There's only one problem with it -- this clever-seeming idiom may not work.

Double-checked locking can be hazardous to your code!

This week JavaWorld focuses on the dangers of the double-checked locking idiom. Read more about how this seemingly harmless shortcut can wreak havoc on your code:


What is DCL?

The DCL idiom was designed to support lazy initialization, which occurs when a class defers initialization of an owned object until it is actually needed:

class SomeClass {
  private Resource resource = null;
  public Resource getResource() {
    if (resource == null)
      resource = new Resource();
    return resource;
  }
}


Why would you want to defer initialization? Perhaps creating a Resource is an expensive operation, and users of SomeClass might not actually call getResource() in any given run. In that case, you can avoid creating the Resource entirely. Regardless, the SomeClass object can be created faster if it doesn't have to also create a Resource at construction time. Delaying some initialization operations until a user actually needs their results can help programs start up faster.

What if you try to use SomeClass in a multithreaded application? Then a race condition results: two threads could simultaneously execute the test to see if resource is null and, as a result, initialize resource twice. In a multithreaded environment, you should declare getResource() to be synchronized.

Unfortunately, synchronized methods run much slower -- as much as 100 times slower -- than ordinary unsynchronized methods. One of the motivations for lazy initialization is efficiency, but it appears that in order to achieve faster program startup, you have to accept slower execution time once the program starts. That doesn't sound like a great trade-off.

DCL purports to give us the best of both worlds. Using DCL, the getResource() method would look like this:

class SomeClass {
  private Resource resource = null;
  public Resource getResource() {
    if (resource == null) {
      synchronized {
        if (resource == null) 
          resource = new Resource();
      }
    }
    return resource;
  }
}


After the first call to getResource(), resource is already initialized, which avoids the synchronization hit in the most common code path. DCL also averts the race condition by checking resource a second time inside the synchronized block; that ensures that only one thread will try to initialize resource. DCL seems like a clever optimization -- but it doesn't work.

Meet the Java Memory Model

More accurately, DCL is not guaranteed to work. To understand why, we need to look at the relationship between the JVM and the computer environment on which it runs. In particular, we need to look at the Java Memory Model (JMM), defined in Chapter 17 of the Java Language Specification, by Bill Joy, Guy Steele, James Gosling, and Gilad Bracha (Addison-Wesley, 2000), which details how Java handles the interaction between threads and memory.

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comments (9)
Login
Forgot your account info?

French fashion and leatherBy Anonymous on November 8, 2009, 1:50 am French fashion and leather goods company Louis Vuitton Louis Vuitton Louis Vuitton Keepall Bandouliere 55 Louis Vuitton Pegase 60 Louis Vuitton Iphone Case Louis...

Reply | Read entire comment

"While thread B may see a valid reference to the newly created RBy Anonymous on September 30, 2009, 3:12 am"While thread B may see a valid reference to the newly created Resource, because it didn't perform a read barrier, it could still see stale values of resource's...

Reply | Read entire comment

No, your implementation isBy Anonymous on September 11, 2009, 9:52 pmNo, your implementation is not safe. Remember, there is no guarantee that 'foo = new Foo();' will excute before 'h =1;'. If it doesn't, then the second thread might...

Reply | Read entire comment

is this implementation safe?By Anonymous on August 27, 2009, 2:59 amclass Foo { private static Foo instance = null; private static int h = 0; private Foo(){} public static Object getInstance() { if (h == 0){ synchronized(this)...

Reply | Read entire comment

Fixed in Java 5By Anonymous on August 18, 2009, 8:24 amThe first commenter is correct. Double-checked locking works in Java 5 as long as the field is declared volatile. See http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html...

Reply | Read entire comment

View all comments

Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.
Resources
  • Double-checked locking idiom:
  • The Java Memory Model and multithreaded programming