Newsletter sign-up
View all newsletters

Sign up for our technology specific newsletters.

Enterprise Java
Email Address:

Can ThreadLocal solve the double-checked locking problem?

ThreadLocal appears to fix the thread-safety issues behind double-checked locking

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
In my previous article "Double-Checked Locking: Clever, but Broken," I looked at some of the problems with double-checked locking (DCL), an idiom recommended by a number of Java books and articles as a way to reduce synchronization overhead when performing lazy initialization. Unfortunately, DCL isn't guaranteed to work under the current Java Memory Model (JMM). The reasons why are subtle, and nearly all the proposed "solutions" are as flawed as the DCL idiom itself -- see "Can Double-Checked Locking Be Fixed?" for some explanations of why this is so. The simple truth is that if threads must share data in a Java program, then you must use synchronization to guarantee that all threads have a consistent view of the data.

The ThreadLocal class, introduced in JDK 1.2, can help reduce some of the complexities involved in developing thread-safe classes by reducing the amount of data shared between threads. But as we shall see, sometimes this simplicity results in performance costs. Let's review the DCL problem and then look at how you can use ThreadLocal to solve part of that problem.

What's wrong with DCL again?

DCL is a technique for lazy initialization; it attempts to eliminate the synchronization overhead on the most common code path when fetching a reference to the lazily initialized object. Developers often try to avoid synchronizing on the common code path because of efficiency issues -- synchronized operations run more slowly than unsynchronized ones. Here is an example of the (incorrect) DCL idiom and the (correct) single-check idiom it was intended to replace:

Listing 1. The double-checked locking (DCL) idiom

// This class is not thread-safe
class DoubleCheckExample { // Not thread-safe
  private static Resource resource = null;
  public static Resource getResource() {
    if (resource == null) {
      synchronized {
        if (resource == null) 
          resource = new Resource();
      }
    }
    return resource;
  }
}
// This class is thread-safe
class SingleCheckExample {
  private static Resource resource = null;
  public static Resource getResource() {
      synchronized {
        if (resource == null) 
          resource = new Resource();
      }
    }
    return resource;
  }
}


Note that in SingleCheckExample, you must execute a synchronized block every time getResource() is called, whereas in DoubleCheckExample, you have to synchronize only the first time. While it appears harmless, DCL doesn't work because the JMM doesn't guarantee that other threads will necessarily see updates to variables made by other threads, unless both threads synchronize on the same monitor. Without synchronizing when you access the shared variable (the resource field), under some architectures and with some unlucky timing, another thread could see a partially constructed Resource returned from getResource(). DCL falls afoul of the synchronization rules by having the first reference to resource, the check to see if it is null, appear outside the synchronized block. In order to guarantee that the Resource object is fully constructed before it is made visible to other threads, you must synchronize.

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comment
Login
Forgot your account info?
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