JavaMemoryModel: First reason on broken Double Check Locking

From: Joe Emporium (joe_emporium@yahoo.com)
Date: Mon Mar 11 2002 - 23:26:29 EST


// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo {
  private Helper helper = null;
  public Helper getHelper() {
    if (helper == null)
      synchronized(this) {
        if (helper == null)
          helper = new Helper();
      }
    return helper;
    }
  // other functions and members...
  }

I can understand from Chapter 8 of JVM Spec (2nd ed) and Chapter 17 of JLS
(2nd ed) the argument about the unpredictable order of write actions of
multiple variables from working copy to the master copy, hence potentially
causing the helper variable in this example to be found to be non-null but
pointing to a partially initialized Helper object.

However, according to Section 2.17.16, page 55, of JVM Spec (2nd ed),

"Just before a reference to the newly created object is returned as the
result, the indicated constructor is processed to initialize the new object
using the following procedure:..." It goes on to describe the detailed
procedure of completing the initialization of the new object, including the
complete execution of the body of the constructor.

So, doesn't the JVM spec clearly states that the newly constructed object
must be complete in terms of it's initialization, BEFORE a reference is
returned ? If so, the JVM must NOT perform a write action to the helper
variable until all write actions for initializing the Helper object have
completed. Otherwise, a reference is returned before the class instance
initialization is complete and the spec is violated.

So the argument

"The most obvious reason it doesn't work it that the writes that initialize
the Helper object and the write to the helper field can be done or perceived
out of order. Thus, a thread which invokes getHelper() could see a non-null
reference to a helper object, but see the default values for fields of the
helper object, rather than the values set in the constructor"

is very interesting but does not seem right to me. In practice the
argument is probably true in terms of pointing out what actually happen in
some JVM implementations, but this only means those implementation are
violating the JVM spec.

It would be a valid argument if the assignment statement in the synchronized
block was a method invocation other than a class instance initialization
(which is explicitly spelled out in the JVM spec in terms of the order of
initialization execution and returning the reference.)

Please comment.

Hanson

-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel



This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:38 EDT