JavaMemoryModel: Semantics of final

From: Bill Pugh (pugh@cs.umd.edu)
Date: Wed Mar 22 2000 - 17:14:47 EST


OK, I think everyone is agreed on the follow basics:

* If you read a final field, you are guaranteed to see the value set
        in the constructor unless:

        * The object escapes before the constructor finishes
        * The thread constructing the object reads the field before it is
          written
        * Native code or reflection is used to change the field

* This guarantee is enforced regardless of data races.

The important question with regards to the semantics:

        * If you read a final field and get a reference to an array or
          object, what guarantees do you have with regards to seeing
          elements/fields of that array/object.

Consider the following code:

        Class Foo {
                final int [] a;
                int [] a2;
                final int [][] b;

                Foo(int x) {
                        int [][] tmp = new int[1][2];
                        tmp[0][0] = x;
                        b = tmp;
                        a = tmp[0];
                        a2 = tmp[0];
                        tmp[0][1] = x;
                        }
                }

F1:
// Are you guaranteed to see non-stale values for fields/elements of
// object referenced by final field?
Initially
Foo f = null;

Thread 1:
f = new Foo(1);

Thread 2:
int i = f.a[0];

Question: Is it possible that i == 0?

F2:
// Does it matter if the writes to the referenced object are done before or
// after the final field is set?
Initially
Foo f = null;

Thread 1:
f = new Foo(1);

Thread 2:
int i = f.a[1];

Question: Is it possible that i == 0?

F3:
// Are you guaranteed to see non-stale values when following pointer chains
// from a final field (e.g., following more than one link).
Initially
Foo f = null;

Thread 1:
f = new Foo(1);

Thread 2:
int i = f.b[0][0];

Question: Is it possible that i == 0?

F4:
// Does it matter if you go through the address loaded, or just which
object you
// reference?
Initially
Foo f = null;

Thread 1:
f = new Foo(1);

Thread 2:
int [] tmp2 = f.a2;
int [] tmp1 = f.a;
int i = tmp2[0];

Question: Is it possible that i == 0?

To get String safety, we must enforce F1. If we enforce F1 but not
F2, then the order in which things are assigned in the constructor
becomes very tricky. A memory order of RMO or stronger is sufficient
to enforce F1 - F3, but not F4 (assuming appropriate barriers are
generated in the constructor).

Enforcing F1 but not F4 is likely to result in rather ugly semantics,
because then the same that you use to load a field/element will
matter.

However, enforcing F4 will require a memory barrier for each load of
a final field on an RMO architecture (and others). It would also mean
that in the code for Thread 2 of F4, a compiler could not reorder the
assignment to tmp1 and i.

        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:24 EDT