Notes on Double-Checked Locking and 32-bit primitive values

Notes on Double-Checked Locking and 32-bit primitive values

To lazily initialize a variable of a reference type in a multithreaded environment, we either use the Initialization-On-Demand Holder or use the Double-Checked Locking with the variable being qualified by the volatile keyword. The variable does not need to be qualified by volatile if it is a 32-bit primitive such as int and float, because there are no "uninitialized non-null" primitives. See The "Double-Checked Locking is Broken" Declaration.

For example, the following code snippet implements a lazily initialized hashCode():

  1. public class Foobar {
  3.   private int hashCode = 0; // no need to be volatile
  5.   @Override
  6.   public int hashCode() {
  7.     int value = hashCode;
  8.     if(0 == value) {
  9.       synchronized(this) {
  10.         value = hashCode;
  11.         if(0 == value) {
  12.           value = initialize(); // return a non-zero value
  13.           hashCode = value;
  14.         }
  15.       }
  16.     }
  17.     return value;
  18.   }
  19. }

The caveats of using this technique are: 1) The uninitialized value and the initialized value need to be different, so that when a thread sees the unintialized value, it knows that it needs to synchronize. 2) This technique only guarantees the memory consistency of the primitive itself to which the technique is applied. The memory consistency of any other shared variable needs to be proved separately to be valid. See the bottom of for the reference of memory consistency properties of commonly used language features.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.

More information about formatting options

To prevent automated spam submissions leave this field empty.