JavaMemoryModel: Synchronization constraints due to class initialization

From: Bill Pugh (pugh@cs.umd.edu)
Date: Thu Jul 13 2000 - 12:02:08 EDT


The JLS says that a class T is initialized when

* T is a class and an instance of T is created.
* T is a class and a static method declared by T is invoked.
* A static field declared by T is assigned.
* A static field declared by T is used and the reference to the field
is not a compile-time constant (§15.28). References to compile-time
constants must be resolved at compile time to a copy of the
compile-time constant value, so uses of such a field never cause
initialization.

The spec also says that class initialization happens at most once.

Although it isn't spelled out, I think the only reasonable
interpretation is that whenever a thread T1 performs an action A that
requires that class C be initialized, if T1 detects that T2 has
already initialized C, then any actions performed by T1 after action
A must see all memory actions resulting from that initialization.

This means, for example, that a reference to a static field of a
class that has not yet been initialized must be treated as a partial
memory barrier; no actions after that reference can be move to before
that reference.

For example, in the following, the first invocation of A.foo must
return 6, not 4.

class A {
   static int x = 1;
   static int foo() {
                return A.x+B.y+A.x;
                }
   }
class B {
   static int y = 2;
   static {
     A.x = 3;
     }
   }

For example, transforming the code for A.foo to return 2*A.x+B.y
would be illegal.

Initially, I was thinking that the actions that force a class T to be
initialized should be expanded to include invokespecial,
invokevirtual, get/putfield. Note that these would never cause the
class to be initialized (because the class must be initialized before
an instance can be created), but they would guarantee that the thread
performing those actions see the results of the initialization.

But now I am concluding that the set of actions should remain the same.

The problem is that otherwise, any of those actions would be a
partial memory barrier in thread T1 unless you could prove that the
run-time type of the object was of a class that had already been seen
to be synchronized by T1.

Thoughts?

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



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