OK, here is a case that shows potential compiler optimizations could
violate feature 2:
class Foo {
final int x;
static Foo p,q;
Foo(int i) {
x = i;
Foo.p = this;
}
}
Thread 1:
synchronized (Foo.class) {
Foo.q = new Foo(42);
}
Thread 2:
Foo a = Foo.p;
if (a != null && a.x == 0)
synchronized (Foo.class) {
Foo b = Foo.q;
if (a == b) {
int i = a.x;
int j = b.x;
// is it possible for j to be zero?
System.out.println(i+j);
}
}
Now, the semantics of final fields allow a compiler to move the load
of a final field a.x to immediately after the load of a (even through
synchronization barriers). So it is possible for i to be zero.
However, the load of b.x cannot be moved to before the lock is
acquired, so j cannot be zero.
However, a compiler writer might be tempted to decide:
* since a and b are equal
* I can reuse the value of a.x as the value of b.x
* getting the value 0 for j
This is a slight variation on an example I posted 2/1/02. Note that
for this example, except for the special semantics of final fields,
it wouldn't be possible for i to be zero anyway (the synchronization
would force a.x to be reloaded).
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:38 EDT