0

Before dismissing this, it is possible to implement double checked locking without volatile, see below. I'm suggesting a variation on this, that gets rid of the local variable.

The following is a correct implementation of double checked locking from Shipilev:

public class FinalWrapperFactory {
  private FinalWrapper wrapper;

  public Singleton get() {
    FinalWrapper w = wrapper;
    if (w == null) { // check 1
      synchronized(this) {
        w = wrapper;
        if (w == null) { // check2
          w = new FinalWrapper(new Singleton());
          wrapper = w;
        }
      }
    }
    return w.instance;
  }

  private static class FinalWrapper {
    public final Singleton instance;
    public FinalWrapper(Singleton instance) {
      this.instance = instance;
    }
  }
}

I wonder if it would be possible to get rid of the local variable w:

public class FinalWrapperFactory {
  private FinalWrapper wrapper; //same as example above

  public Singleton get() {
    if (wrapper == null) { // read 1
      synchronized(this) {
        if (wrapper == null) { // read 2
          wrapper = new FinalWrapper(new Singleton());
          return wrapper.instance; // read 3
        } else {
          return wrapper.instance; // read 4 
        }
      }
    } else {
      return wrapper.instance; // read 5 (last read). Can this be reordered?
    }
  }
}

In 17.4.8. Executions and Causality Requirements of the JLS 8 it is written:

Informally, we allow an action to be committed early if we know that the action can occur without assuming some data race occurs.

The big question here is if the last read (read 5) can be reordered so that we could potentially see a non-null wrapper in read 1 and still see a null in the last read. This should not be allowed to happen in the first invocation of get() by a thread because then the only way for the last read to occur would be because of a data race and the JMM would prohibit the reordering.

In subsequent invocations of get() reordering would be allowed but then it shouldn't matter because wrapper should be visible anyways.

Roland
  • 7,525
  • 13
  • 61
  • 124
  • 3
    As an aside: the very fact that this code is subtle and hard to get right should be a sign that this isn't an optimal solution. Prefer something like an [initialization on demand holder idiom](https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom) in real code. – Daniel Pryden May 15 '16 at 15:16
  • @DanielPryden I agree, for me it is just a way to evaluate my understanding of multi threading. – Roland May 15 '16 at 15:21
  • [Does double-checked locking ever work](http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)? – Basilevs May 16 '16 at 03:03
  • Possible duplicate of [Why is volatile used in this example of double checked locking](http://stackoverflow.com/questions/7855700/why-is-volatile-used-in-this-example-of-double-checked-locking) – Basilevs May 16 '16 at 03:07
  • Please see a Related panel to the left. Most questions there are duplicates of this. Answers are not bad too. – Basilevs May 16 '16 at 03:08
  • @Basilevs It is possible to do double checked locking without volatile, check the link to Shipilev at the beginning of my question. I'm suggesting a variation on this, also without volatile. So the provided suggestions don't answer my question. – Roland May 16 '16 at 16:47

0 Answers0