title: Double-checked locking without volatile
body: <p>I read <a href="https://stackoverflow.com/questions/3578604/how-to-solve-the-double-checked-locking-is-broken-declaration-in-java/3580658#3580658">this question</a> about how to do Double-checked locking:</p>
  
  <pre><code>// Double-check idiom for lazy initialization of instance fields
  private volatile FieldType field;
  FieldType getField() {
      FieldType result = field;
      if (result == null) { // First check (no locking)
          synchronized(this) {
              result = field;
              if (result == null) // Second check (with locking)
                  field = result = computeFieldValue();
          }
      }
      return result;
  }
  </code></pre>
  
  <p>My aim is to get lazy-loading a field (NOT a singleton) work without the volatile attribute. The field object is never changed after initialization. </p>
  
  <p>After some testing my final approach:</p>
  
  <pre><code>    private FieldType field;
  
      FieldType getField() {
          if (field == null) {
              synchronized(this) {
                  if (field == null)
                      field = Publisher.publish(computeFieldValue());
              }
          }
          return fieldHolder.field;
      }
  
  
  
  public class Publisher {
  
      public static &lt;T&gt; T publish(T val){
          return new Publish&lt;T&gt;(val).get();
      }
  
      private static class Publish&lt;T&gt;{
          private final T val;
  
          public Publish(T val) {
              this.val = val;
          }
  
          public T get(){
              return val;
          }
      }
  }
  </code></pre>
  
  <p>The benefit is possibly faster access time due to not needing volatile, while still keeping the simplicity with the reusable Publisher class.</p>
  
  <hr>
  
  <p>I tested this using jcstress. SafeDCLFinal worked as expected while UnsafeDCLFinal was inconsistent (as expected). At this point im 99% sure it works, but please, prove me wrong. Compiled with <code>mvn clean install -pl tests-custom -am</code> and run with <code>java -XX:-UseCompressedOops -jar tests-custom/target/jcstress.jar -t DCLFinal</code>. Testing code below (mostly modified singleton testing classes):</p>
  
  <pre><code>/*
   * SafeDCLFinal.java:
   */
  
  package org.openjdk.jcstress.tests.singletons;
  
  public class SafeDCLFinal {
  
      @JCStressTest
      @JCStressMeta(GradingSafe.class)
      public static class Unsafe {
          @Actor
          public final void actor1(SafeDCLFinalFactory s) {
              s.getInstance(SingletonUnsafe::new);
          }
  
          @Actor
          public final void actor2(SafeDCLFinalFactory s, IntResult1 r) {
              r.r1 = Singleton.map(s.getInstance(SingletonUnsafe::new));
          }
      }
  
      @JCStressTest
      @JCStressMeta(GradingSafe.class)
      public static class Safe {
          @Actor
          public final void actor1(SafeDCLFinalFactory s) {
              s.getInstance(SingletonSafe::new);
          }
  
          @Actor
          public final void actor2(SafeDCLFinalFactory s, IntResult1 r) {
              r.r1 = Singleton.map(s.getInstance(SingletonSafe::new));
          }
      }
  
  
      @State
      public static class SafeDCLFinalFactory {
          private Singleton instance; // specifically non-volatile
  
          public Singleton getInstance(Supplier&lt;Singleton&gt; s) {
              if (instance == null) {
                  synchronized (this) {
                      if (instance == null) {
  //                      instance = s.get();
                          instance = Publisher.publish(s.get(), true);
                      }
                  }
              }
              return instance;
          }
      }
  }
  
  /*
   * UnsafeDCLFinal.java:
   */
  
  package org.openjdk.jcstress.tests.singletons;
  
  public class UnsafeDCLFinal {
  
      @JCStressTest
      @JCStressMeta(GradingUnsafe.class)
      public static class Unsafe {
          @Actor
          public final void actor1(UnsafeDCLFinalFactory s) {
              s.getInstance(SingletonUnsafe::new);
          }
  
          @Actor
          public final void actor2(UnsafeDCLFinalFactory s, IntResult1 r) {
              r.r1 = Singleton.map(s.getInstance(SingletonUnsafe::new));
          }
      }
  
      @JCStressTest
      @JCStressMeta(GradingUnsafe.class)
      public static class Safe {
          @Actor
          public final void actor1(UnsafeDCLFinalFactory s) {
              s.getInstance(SingletonSafe::new);
          }
  
          @Actor
          public final void actor2(UnsafeDCLFinalFactory s, IntResult1 r) {
              r.r1 = Singleton.map(s.getInstance(SingletonSafe::new));
          }
      }
  
      @State
      public static class UnsafeDCLFinalFactory {
          private Singleton instance; // specifically non-volatile
  
          public Singleton getInstance(Supplier&lt;Singleton&gt; s) {
              if (instance == null) {
                  synchronized (this) {
                      if (instance == null) {
  //                      instance = s.get();
                          instance = Publisher.publish(s.get(), false);
                      }
                  }
              }
              return instance;
          }
      }
  }
  
  /*
   * Publisher.java:
   */
  
  package org.openjdk.jcstress.tests.singletons;
  
  public class Publisher {
  
      public static &lt;T&gt; T publish(T val, boolean safe){
          if(safe){
              return new SafePublish&lt;T&gt;(val).get();
          }
          return new UnsafePublish&lt;T&gt;(val).get();
      }
  
      private static class UnsafePublish&lt;T&gt;{
          T val;
  
          public UnsafePublish(T val) {
              this.val = val;
          }
  
          public T get(){
              return val;
          }
      }
  
      private static class SafePublish&lt;T&gt;{
          final T val;
  
          public SafePublish(T val) {
              this.val = val;
          }
  
          public T get(){
              return val;
          }
      }
  }
  </code></pre>
  
  <p>Tested with java 8, but should work at least with java 6+. <a href="http://docs.oracle.com/javase/specs/jls/se6/html/memory.html#17.5" rel="noreferrer">See docs</a></p>
  
  <hr>
  
  <p>But I wonder if this would work:</p>
  
  <pre><code>    // Double-check idiom for lazy initialization of instance fields without volatile
      private FieldHolder fieldHolder = null;
      private static class FieldHolder{
          public final FieldType field;
          FieldHolder(){
              field = computeFieldValue();
          }
      }
  
      FieldType getField() {
          if (fieldHolder == null) { // First check (no locking)
              synchronized(this) {
                  if (fieldHolder == null) // Second check (with locking)
                      fieldHolder = new FieldHolder();
              }
          }
          return fieldHolder.field;
      }
  </code></pre>
  
  <p>Or maybe even:</p>
  
  <pre><code>    // Double-check idiom for lazy initialization of instance fields without volatile
      private FieldType field = null;
      private static class FieldHolder{
          public final FieldType field;
  
          FieldHolder(){
              field = computeFieldValue();
          }
      }
  
      FieldType getField() {
          if (field == null) { // First check (no locking)
              synchronized(this) {
                  if (field == null) // Second check (with locking)
                      field = new FieldHolder().field;
              }
          }
          return field;
      }
  </code></pre>
  
  <p>Or:</p>
  
  <pre><code>    // Double-check idiom for lazy initialization of instance fields without volatile
      private FieldType field = null;
  
      FieldType getField() {
          if (field == null) { // First check (no locking)
              synchronized(this) {
                  if (field == null) // Second check (with locking)
                      field = new Object(){
                          public final FieldType field = computeFieldValue();
                      }.field;
              }
          }
          return field;
      }
  </code></pre>
  
  <p>I belive this would work based on <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5" rel="noreferrer">this oracle doc</a>: </p>
  
  <blockquote>
    <p>The usage model for final fields is a simple one: Set the final fields for an object in that object's constructor; and do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then <strong>when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields</strong>. It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are. </p>
  </blockquote>