Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Wiki Markup
"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." \[[Bloch 08|AA. Java References#Bloch 08]\].  

Compliant Solution (

...

static initialization)

Wiki Markup
This compliant solution initializes the {{helper}} in the declaration of the {{static}} variable \[[Manson 06|AA. Java References#Manson 06]\]. 
In this solution the Foo class is unchanged, but the Helper class is immutable. In this case, the Helper class is guaranteed to be fully constructed before becoming visible. The object must be truly immutable; it is not sufficient for the program to refrain from modifying the object.

Code Block
bgColor#CCCCFF#ccccff
public class HelperFoo {
  private static final Helper int nhelper = new Helper(42);

  public static Helper getHelper(int n) {
    this.n = n;
  }

  // other fields & methods,return helper;}
}

Variables declared static are guaranteed to be initialized and made visible to other threads immediately. Static initializers also exhibit these properties. This approach should not be confused with eager initialization because in this case, the Java Language Specification guarantees lazy initialization of the class when it is first used.

Compliant Solution (initialize-on-demand holder class idiom)

This compliant solution explicitly incorporates lazy initialization. It also uses a static variable as suggested in the previous compliant solution. The variable is declared within a static inner, Holder class.

Code Block
bgColor#ccccff
 all fields are final
}

class Foo {
  privatestatic Helper helper = null;
  
  public// HelperLazy getHelper()initialization { 
    if (helper == null) {
      synchronized(this)private static class Holder {
    static Helper helper = ifnew Helper(helper == null) {);
  }

  public static Helper getInstance() {
  helper = new Helper(); // If the helper is null, create a new instance
        }
      }
    }
    return helper; // If helper is non-null, return its instance
  }
}

Note that if Foo was mutable, the Helper field would need to be declared volatile as shown in CON00-J. Declare status flags as volatile. Also, the method getHelper() is an instance method and the accessibility of the helper field is private. This allows safe publication of the Helper object, in that, a thread cannot observe a partially initialized Foo object (CON26-J. Do not publish partially-constructed objects).

...

return Holder.helper;
  }
}

Wiki Markup
This idiom is called the initialize-on-demand holder class idiom. Initialization of the {{Holder}} class is deferred until the {{getInstance()}} method is called, following which the {{helper}} is initialized. The only limitation of this method is that it works only for {{static}} fields and not instance fields \[[Bloch 01|AA. Java References#Bloch 01]\]. This idiom is a better choice than the double checked locking idiom for lazily initializing {{static}} fields \[[Bloch 08|AA. Java References#Bloch 08]\].

Compliant Solution (ThreadLocal storage)

Wiki Markup
This compliant solution initializes(originally the {{helper}} in the declaration of the {{static}} variablesuggested by Alexander Terekhov \[[MansonPugh 0604|AA. Java References#MansonReferences#Pugh 0604]\]. 

...

bgColor#ccccff

...

)

...

 

...

uses a {{ThreadLocal}} object to lazily create a {{Helper}} instance.

Code Block
bgColor#ccccff

class Foo {
  // If perThreadInstance.get() returns a non-null value, this thread
  // has done synchronization needed to see initialization of helper

  private final ThreadLocal perThreadInstance = new ThreadLocal();
  private Helper helper = null;

  public Helper getHelper() {
    if (perThreadInstance.get() == null)

Variables declared static are guaranteed to be initialized and made visible to other threads immediately. Static initializers also exhibit these properties. This approach should not be confused with eager initialization because in this case, the Java Language Specification guarantees lazy initialization of the class when it is first used.

Compliant Solution (initialize-on-demand holder class idiom)

This compliant solution explicitly incorporates lazy initialization. It also uses a static variable as suggested in the previous compliant solution. The variable is declared within a static inner, Holder class.

Code Block
bgColor#ccccff

class Foo {
  static Helper helper;

  // Lazy initialization 
  private static class Holder {
    static Helper helper = new Helper createHelper();
  }

  public static Helper getInstance() {}
    return Holder.helper;
  }
}

Wiki Markup
This idiom is called the initialize-on-demand holder class idiom. Initialization of the {{Holder}} class is deferred until the {{getInstance()}} method is called, following which the {{helper}} is initialized. The only limitation of this method is that it works only for {{static}} fields and not instance fields \[[Bloch 01|AA. Java References#Bloch 01]\]. This idiom is a better choice than the double checked locking idiom for lazily initializing {{static}} fields \[[Bloch 08|AA. Java References#Bloch 08]\].

Compliant Solution (ThreadLocal storage)

Wiki Markup
This compliant solution (originally suggested by Alexander Terekhov \[[Pugh 04|AA. Java References#Pugh 04]\]) uses a {{ThreadLocal}} object to lazily create a {{Helper}} instance.

}
        
  private final void createHelper() {
    synchronized(this) {
      if (helper == null) {
        helper = new Helper();
      }
      // Any non-null value would do as the argument here
      perThreadInstance.set(perThreadInstance);
    }
  }
}

Compliant Solution (immutable)

In this solution the Foo class is unchanged, but the Helper class is immutable. In this case, the Helper class is guaranteed to be fully constructed before becoming visible. The object must be truly immutable; it is not sufficient for the program to refrain from modifying the object.

Code Block
bgColor#CCCCFF

public class Helper {
  private final int n;

  public Helper(int n) {
    this.n = n;
  }

  // other fields & methods, all fields are final
}

class Foo {
  private Helper helper = null;
  
  public Helper getHelper() { 
    if (helper == null) {
      synchronized(this
Code Block
bgColor#ccccff

class Foo {
  // If perThreadInstance.get() returns a non-null value, this thread
  // has done synchronization needed to see initialization of helper

  private final ThreadLocal perThreadInstance = new ThreadLocal();
  private Helper helper = null;

  public Helper getHelper() {
        if (perThreadInstance.get()helper == null) {
      createHelper();
    }
helper =   return helper;
  }
        
  private final void createHelper() {
    synchronized(this) {new Helper(); // If the helper is null, create a new instance
        }
      if}
 (helper == null) {}
    return helper; // If helper = new Helper();
      }
      // Any non-null value would do as the argument here
      perThreadInstance.set(perThreadInstance);
    }
  }
}
is non-null, return its instance
  }
}

Note that if Foo was mutable, the Helper field would need to be declared volatile as shown in CON00-J. Declare status flags as volatile. Also, the method getHelper() is an instance method and the accessibility of the helper field is private. This allows safe publication of the Helper object, in that, a thread cannot observe a partially initialized Foo object (CON26-J. Do not publish partially-constructed objects).

Exceptions

EX1: Explicitly synchronized code (that uses method synchronization or proper block synchronization, that is, enclosing all initialization statements) does not require the use of double-checked locking.

Wiki Markup
*EX2:* "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." \[[Pugh 04|AA. Java References#Pugh 04]\]. See [CON25-J. Ensure atomicity when reading and writing 64-bit values] for more Informationinformation. 

Risk Assessment

Using incorrect forms of the double checked locking idiom can lead to synchronization issues.

...