39

I want to implement lazy initialization for multithreading in Java.
I have some code of the sort:

class Foo {
    private Helper helper = null;
    public Helper getHelper() {
        if (helper == null) {
            Helper h;
            synchronized(this) {
                h = helper;
                if (h == null) 
                    synchronized (this) {
                        h = new Helper();
                    } // release inner synchronization lock
                helper = h;
            } 
        }    
        return helper;
    }
    // other functions and members...
}

And I'm getting the the "Double-Checked Locking is Broken" declaration.
How can I solve this?

Hosam Aly
  • 38,883
  • 35
  • 132
  • 179
monsieurBelbo
  • 667
  • 1
  • 7
  • 15
  • Double-check locking has been fixed, check Effective Java 2nd Edition for more details on how to do this. – gpampara Aug 26 '10 at 20:02
  • 1
    You don't need the inner synchronize statement in any case since you are already in one. – Robin Aug 26 '10 at 20:26
  • This is only a problem if new Helper() can never throw an exception. Also never an OOME. If there any new Object() in the constructor then it is no problem. The constructor must also not empty. If the constructor is such simple then it is simpler to create the object not lazy. – Horcrux7 Jun 17 '17 at 10:29

9 Answers9

85

Here is the idiom recommended in the Item 71: Use lazy initialization judiciously of Effective Java:

If you need to use lazy initialization for performance on an instance field, use the double-check idiom. This idiom avoids the cost of locking when accessing the field after it has been initialized (Item 67). The idea behind the idiom is to check the value of the field twice (hence the name double-check): once without locking, and then, if the field appears to be uninitialized, a second time with locking. Only if the second check indicates that the field is uninitialized does the call initialize the field. Because there is no locking if the field is already initialized, it is critical that the field be declared volatile (Item 66). Here is the idiom:

// Double-check idiom for lazy initialization of instance fields
private volatile FieldType field;

private FieldType getField() {
    FieldType result = field;
    if (result != null) // First check (no locking)
        return result;
    synchronized(this) {
        if (field == null) // Second check (with locking)
            field = computeFieldValue();
        return field;
    }
}

This code may appear a bit convoluted. In particular, the need for the local variable result may be unclear. What this variable does is to ensure that field is read only once in the common case where it’s already initialized. While not strictly necessary, this may improve performance and is more elegant by the standards applied to low-level concurrent programming. On my machine, the method above is about 25 percent faster than the obvious version without a local variable.

Prior to release 1.5, the double-check idiom did not work reliably because the semantics of the volatile modifier were not strong enough to support it [Pugh01]. The memory model introduced in release 1.5 fixed this problem [JLS, 17, Goetz06 16]. Today, the double-check idiom is the technique of choice for lazily initializing an instance field. While you can apply the double-check idiom to static fields as well, there is no reason to do so: the lazy initialization holder class idiom is a better choice.

Reference

  • Effective Java, Second Edition
    • Item 71: Use lazy initialization judiciously
Anton
  • 392
  • 2
  • 18
Pascal Thivent
  • 535,937
  • 127
  • 1,027
  • 1,106
  • 11
    The **one and only correct answer** to the questions about double-checked locking in all of Stack Overflow. Just wanted to add a statement by Joshua Bloch, the author of the book that is referred to in this answer. In an interview (http://www.oracle.com/technetwork/articles/javase/bloch-effective-08-qa-140880.html), said: "The idiom is very fast but also complicated and delicate, so don't be tempted to modify it in any way. Just copy and paste -- normally not a good idea, but appropriate here". Just a warning for anyone who might be tempted to try to "improve" on the above code. :-) – Ajoy Bhatia Oct 30 '15 at 20:33
  • 1
    @Pascal Thivent I have **two questions** on the code sample. **1)** Why `result = field;` is needed inside the SYNC block? SYNC itself enough to update the thread right? e.g.) `if (field== null) // Second check (with locking)` **2)** Assigning the value to result is needed at the last? `result = computeFieldValue();` – Kanagavelu Sugumar Dec 11 '15 at 08:55
  • @KanagaveluSugumar **1)** Actually I wonder that too, your logic seems correct to me. **2)** Assigning the value to result first ensures (apparently) that the constructor is executed fully first, and only then field is updated (fixing the core problem of double-checked locking). Only thing I wonder here is why the compiler doesn't optimize away the assignment to a local variable that is not used afterwards. Apparently it can be assumed that it doesn't do that. – Stefan Reich Aug 28 '17 at 12:32
  • 3
    Joshua Bloch, corrected this example. Here is his twitter post https://twitter.com/joshbloch/status/964327677816532992. And here is the official errata for the book http://ptgmedia.pearsoncmg.com/imprint_downloads/informit/bookreg/9780134685991/EffectiveJava3E_errata_08152018.pdf – Anton Apr 21 '19 at 09:34
  • Does this example still hold if we need to make field "field" static? private static volatile FieldType field; private static FieldType getField() {) – Steven Feb 20 '20 at 23:11
  • 1
    @Anton, thanks for sharing the errata, but I think the prevision version was correct also. It was an intermediate version that had definition like - `FieldType result = field; if (result == null) {synchronized(this) {if (field == null) field = result = computeFieldValue();}} return result;` that was incorrect because the synchronized block doesn't update the `result` in case `field!=null` causing `result` which is still null to be returned from the method – user11981729 May 08 '20 at 09:38
13

Here is a pattern for correct double-checked locking.

class Foo {

  private volatile HeavyWeight lazy;

  HeavyWeight getLazy() {
    HeavyWeight tmp = lazy; /* Minimize slow accesses to `volatile` member. */
    if (tmp == null) {
      synchronized (this) {
        tmp = lazy;
        if (tmp == null) 
          lazy = tmp = createHeavyWeightObject();
      }
    }
    return tmp;
  }

}

For a singleton, there is a much more readable idiom for lazy initialization.

class Singleton {
  private static class Ref {
    static final Singleton instance = new Singleton();
  }
  public static Singleton get() {
    return Ref.instance;
  }
}
erickson
  • 249,448
  • 50
  • 371
  • 469
  • A very interesting idea. Of course, it won't work in cases where you don't want to use the singleton pattern. – Mike Baranczak Aug 26 '10 at 19:29
  • 2
    the question is about a non static field. – irreputable Aug 26 '10 at 19:47
  • @erickson I have **two questions** on the code sample. **1)** Why `tmp= lazy;` is needed inside the SYNC block? SYNC itself enough to update the thread right? so we can check only on `if (lazy== null)` inside SYNC instead `if (temp== null)` **2)** Assigning the value to result is needed at the last? `tmp = createHeavyWeightObject();` – Kanagavelu Sugumar Dec 11 '15 at 09:04
  • @KanagaveluSugumar The **(1)** first assignment to `tmp` is there to save an extra read of the `volatile` variable, `lazy`; the assumption is that reading a volatile variable is much slower than storing a local variable. The **(2)** second assignment supports a single `return`, which is a stylistic choice for readability. – erickson Dec 12 '15 at 19:03
  • @erickson Fine, Thankyou! – Kanagavelu Sugumar Dec 14 '15 at 11:45
5

DCL using ThreadLocal By Brian Goetz @ JavaWorld

what's broken about DCL?

DCL relies on an unsynchronized use of the resource field. That appears to be harmless, but it is not. To see why, imagine that thread A is inside the synchronized block, executing the statement resource = new Resource(); while thread B is just entering getResource(). Consider the effect on memory of this initialization. Memory for the new Resource object will be allocated; the constructor for Resource will be called, initializing the member fields of the new object; and the field resource of SomeClass will be assigned a reference to the newly created object.

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

However, since thread B is not executing inside a synchronized block, it may see these memory operations in a different order than the one thread A executes. It could be the case that B sees these events in the following order (and the compiler is also free to reorder the instructions like this): allocate memory, assign reference to resource, call constructor. Suppose thread B comes along after the memory has been allocated and the resource field is set, but before the constructor is called. It sees that resource is not null, skips the synchronized block, and returns a reference to a partially constructed Resource! Needless to say, the result is neither expected nor desired.

Can ThreadLocal help fix DCL?

We can use ThreadLocal to achieve the DCL idiom's explicit goal -- lazy initialization without synchronization on the common code path. Consider this (thread-safe) version of DCL:

Listing 2. DCL using ThreadLocal

class ThreadLocalDCL {
  private static ThreadLocal initHolder = new ThreadLocal();
  private static Resource resource = null;
  public Resource getResource() {
    if (initHolder.get() == null) {
      synchronized {
        if (resource == null) 
          resource = new Resource();
        initHolder.set(Boolean.TRUE);
      }
    }
    return resource;
  }
}

I think; here each thread will once enters the SYNC block to update the threadLocal value; then it will not. So ThreadLocal DCL will ensure a thread will enter only once inside the SYNC block.

What does synchronized really mean?

Java treats each thread as if it runs on its own processor with its own local memory, each talking to and synchronizing with a shared main memory. Even on a single-processor system, that model makes sense because of the effects of memory caches and the use of processor registers to store variables. When a thread modifies a location in its local memory, that modification should eventually show up in the main memory as well, and the JMM defines the rules for when the JVM must transfer data between local and main memory. The Java architects realized that an overly restrictive memory model would seriously undermine program performance. They attempted to craft a memory model that would allow programs to perform well on modern computer hardware while still providing guarantees that would allow threads to interact in predictable ways.

Java's primary tool for rendering interactions between threads predictably is the synchronized keyword. Many programmers think of synchronized strictly in terms of enforcing a mutual exclusion semaphore (mutex) to prevent execution of critical sections by more than one thread at a time. Unfortunately, that intuition does not fully describe what synchronized means.

The semantics of synchronized do indeed include mutual exclusion of execution based on the status of a semaphore, but they also include rules about the synchronizing thread's interaction with main memory. In particular, the acquisition or release of a lock triggers a memory barrier -- a forced synchronization between the thread's local memory and main memory. (Some processors -- like the Alpha -- have explicit machine instructions for performing memory barriers.) When a thread exits a synchronized block, it performs a write barrier -- it must flush out any variables modified in that block to main memory before releasing the lock. Similarly, when entering a synchronized block, it performs a read barrier -- it is as if the local memory has been invalidated, and it must fetch any variables that will be referenced in the block from main memory.

Kanagavelu Sugumar
  • 16,614
  • 19
  • 77
  • 92
3

The only way to do double-checked locking correctly in Java is to use "volatile" declarations on the variable in question. While that solution is correct, note that "volatile" means cache lines get flushed at every access. Since "synchronized" flushes them at the end of the block, it may not actually be any more efficient (or even less efficient). I'd recommend just not using double-checked locking unless you've profiled your code and found there to be a performance problem in this area.

samkass
  • 5,554
  • 2
  • 19
  • 25
  • 1
    I see your answer doesn't use volatile and is correct, but it's also likely no faster since it requires two objects and an extra memory fetch. The bottom line is still that double-checked locking is likely a marginal performance gain at best and you shouldn't bother with it unless your profiling shows it to be extremely performance-critical code... it's too easy to get wrong and/or introduce difficult-to-find problems for little gain. – samkass Aug 27 '10 at 00:29
  • on average volatile read causes more memory fetches, because cache line is flushed. the presence of volatile kills optimization. if we change all our variables to volatile, out programs will crap out. – irreputable Aug 27 '10 at 18:33
2

Define the variable that should be double-checked with volatile midifier

You don't need the h variable. Here is an example from here

class Foo {
    private volatile Helper helper = null;
    public Helper getHelper() {
        if (helper == null) {
            synchronized(this) {
                if (helper == null)
                    helper = new Helper();
            }
        }
        return helper;
    }
}
jutky
  • 3,746
  • 6
  • 29
  • 43
2

what do you mean, from whom you are getting the declaration?

Double-Checked Locking is fixed. check wikipedia:

public class FinalWrapper<T>
{
    public final T value;
    public FinalWrapper(T value) { this.value = value; }
}

public class Foo
{
   private FinalWrapper<Helper> helperWrapper = null;
   public Helper getHelper()
   {
      FinalWrapper<Helper> wrapper = helperWrapper;
      if (wrapper == null)
      {
          synchronized(this)
          {
              if (helperWrapper ==null)
                  helperWrapper = new FinalWrapper<Helper>( new Helper() );
              wrapper = helperWrapper;
          }
      }
      return wrapper.value;
   }
irreputable
  • 42,827
  • 9
  • 59
  • 89
2

As a few have noted, you definitely need the volatile keyword to make it work correctly, unless all members in the object are declared final, otherwise there is no happens-before pr safe-publication and you could see the default values.

We got sick of the constant problems with people getting this wrong, so we coded a LazyReference utility that has final semantics and has been profiled and tuned to be as fast as possible.

Jed Wesley-Smith
  • 4,516
  • 16
  • 20
2

Copying below from somewhere else ,which explains why using a method local variable as a copy for the volatile variable will speed things up.

Statement that needs explanation:

This code may appear a bit convoluted. In particular, the need for the local variable result may be unclear.

Explanation:

The field would be read first time in the first if statement and second time in the return statement. The field is declared volatile, which means it has to be refetched from memory every time it is accessed (roughly speaking, even more processing might be required to access volatile variables) and can not be stored into a register by the compiler. When copied to the local variable and then used in both statements (if and return), the register optimization can be done by the JVM.

-2

If I'm not mistaken, there is also another solution if we do not want to use the volatile keyword

for example by taking the previous example

    class Foo {
        private Helper helper = null;
        public Helper getHelper() {
            if (helper == null) {
                synchronized(this) {
                    if (helper == null)
                        Helper newHelper = new Helper();
                        helper = newHelper;
                }
            }
            return helper;
        }
     }

the test is always on the helper variable but the construction of the object is done just before with the newHelper, it avoids to have a partially constructed object