Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Can ThreadLocal solve the double-checked locking problem?

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

  • Print
  • Feedback
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.

  • Print
  • Feedback

Resources