Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to solve the "Double-Checked Locking is Broken" Declaration in Java?

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?

like image 276
monsieurBelbo Avatar asked Aug 26 '10 19:08

monsieurBelbo


People also ask

Why double checked locking is broken?

Although the double-checked locking idiom cannot be used for references to objects, it can work for 32-bit primitive values (e.g., int's or float's). Note that it does not work for long's or double's, since unsynchronized reads/writes of 64-bit primitives are not guaranteed to be atomic.

What is double checked locking in Java?

In double-checked locking, code checks for an existing instance of Singleton class twice with and without locking to make sure that only one instance of singleton gets created.

Can the double checked locking fail on a single processor system?

Ans. There is no mapping of single ton with number of processor of the system. So double check locking will not fail depending on number of processor.

Is double checked locking bad?

Double checked locking is safe in Java, PROVIDED THAT: the instance variable is declared as volatile , AND. the JVM correctly implements the JSR-133 specification; i.e. it is compliant with Java 5 and later.


2 Answers

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
like image 146
Pascal Thivent Avatar answered Oct 06 '22 02:10

Pascal Thivent


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;   } } 
like image 20
erickson Avatar answered Oct 06 '22 00:10

erickson