Rather than discuss specific instances where I've made changes to ensure
an object reference doesn't escape during construction, I figure it
would be more constructive to discuss final fields themselves.
Some of the arguments against using Startable were based on timing when
references to partially constructed objects would be accessed, this is
incorrect. REF: JLS 17.5.1 Semantics of final fields, final paragraph
"For reads of |final| fields, the only writes that are deemed to come
before the read of the |final| field are the ones derived through the
|final| field semantics." The problem was that the execution path from
our service instances to the location where other threads read its
reference, did not pass through a final field freeze at the end of a
constructor; the compiler is under no obligation to reload these final
fields.
The argument that ensued over Startable could have been avoided if
someone simply proposed they preferred to use a public constructor that
publishes and exports, after calling a private constructor that sets
final fields, that would have also been correct. REF: JLS 17.5.1
Semantics of final fields, paragraph 2.
Does anyone here on the list still think it's acceptable to allow the
reference of an object that has final fields to escape from the
constructor that sets those final fields as our services in River 2.2
and all earlier releases of Jini do?
Welcome to theoretical development.
The relevant section of the Java 7 Language Specification:
17.5. |final| Field Semantics
Fields declared final are initialized once, but never changed under
normal circumstances. The detailed semantics of |final| fields are
somewhat different from those of normal fields. In particular, compilers
have a great deal of freedom to move reads of |final| fields across
synchronization barriers and calls to arbitrary or unknown methods.
Correspondingly, compilers are allowed to keep the value of a |final|
field cached in a register and not reload it from memory in situations
where a non-|final| field would have to be reloaded.
|final| fields also allow programmers to implement thread-safe immutable
objects without synchronization. A thread-safe immutable object is seen
as immutable by all threads, even if a data race is used to pass
references to the immutable object between threads. This can provide
safety guarantees against misuse of an immutable class by incorrect or
malicious code. |final| fields must be used correctly to provide a
guarantee of immutability.
An object is considered to be /completely initialized/ when its
constructor finishes. A thread that can only see a reference to an
object after that object has been completely initialized is guaranteed
to see the correctly initialized values for that object's |final| fields.
The usage model for |final| fields is a simple one: Set the |final|
fields for an object in that object's constructor; and do not write a
reference to the object being constructed in a place where another
thread can see it before the object's constructor is finished. If this
is followed, then when the object is seen by another thread, that thread
will always see the correctly constructed version of that object's
|final| fields. It will also see versions of any object or array
referenced by those |final| fields that are at least as up-to-date as
the |final| fields are.
*Example 17.5-1. |final| Fields In The Java Memory Model*
The program below illustrates how |final| fields compare to normal fields.
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader() {
if (f != null) {
int i = f.x; // guaranteed to see 3
int j = f.y; // could see 0
}
}
}
The class |FinalFieldExample| has a |final| |int| field |x| and a
non-|final| |int| field |y|. One thread might execute the method
|writer| and another might execute the method |reader|.
Because the |writer| method writes |f| /after/ the object's constructor
finishes, the |reader| method will be guaranteed to see the properly
initialized value for |f.x|: it will read the value |3|. However, |f.y|
is not |final|; the |reader| method is therefore not guaranteed to see
the value |4| for it.
*Example 17.5-2. |final| Fields For Security*
|final| fields are designed to allow for necessary security guarantees.
Consider the following program. One thread (which we shall refer to as
thread 1) executes:
Global.s = "/tmp/usr".substring(4);
while another thread (thread 2) executes
String myS = Global.s;
if (myS.equals("/tmp"))System.out.println(myS);
|String| objects are intended to be immutable and string operations do
not perform synchronization. While the |String| implementation does not
have any data races, other code could have data races involving the use
of |String| objects, and the memory model makes weak guarantees for
programs that have data races. In particular, if the fields of the
|String| class were not |final|, then it would be possible (although
unlikely) that thread 2 could initially see the default value of |0| for
the offset of the string object, allowing it to compare as equal to
"|/tmp|". A later operation on the |String| object might see the correct
offset of |4|, so that the |String| object is perceived as being
"|/usr|". Many security features of the Java programming language depend
upon |String| objects being perceived as truly immutable, even if
malicious code is using data races to pass |String| references between
threads.
17.5.1. Semantics of |final| Fields
Let /o/ be an object, and /c/ be a constructor for /o/ in which a
|final| field /f/ is written. A /freeze/ action on |final| field /f/ of
/o/ takes place when /c/ exits, either normally or abruptly.
Note that if one constructor invokes another constructor, and the
invoked constructor sets a |final| field, the freeze for the |final|
field takes place at the end of the invoked constructor.
For each execution, the behavior of reads is influenced by two
additional partial orders, the dereference chain /dereferences()/ and
the memory chain /mc()/, which are considered to be part of the
execution (and thus, fixed for any particular execution). These partial
orders must satisfy the following constraints (which need not have a
unique solution):
*
Dereference Chain: If an action /a/ is a read or write of a field
or element of an object /o/ by a thread /t/ that did not
initialize /o/, then there must exist some read /r/ by thread /t/
that sees the address of /o/ such that /r/ /dereferences(r, a)/.
*
Memory Chain: There are several constraints on the memory chain
ordering:
o
If /r/ is a read that sees a write /w/, then it must be the
case that /mc(w, r)/.
o
If /r/ and /a/ are actions such that /dereferences(r, a)/,
then it must be the case that /mc(r, a)/.
o
If /w/ is a write of the address of an object /o/ by a
thread /t/ that did not initialize /o/, then there must
exist some read /r/ by thread /t/ that sees the address of
/o/ such that /mc(r, w)/.
Given a write /w/, a freeze /f/, an action /a/ (that is not a read of a
|final| field), a read /r_1 / of the |final| field frozen by /f/, and a
read /r_2 / such that /hb(w, f)/, /hb(f, a)/, /mc(a, r_1 )/, and
/dereferences(r_1 , r_2 )/, then when determining which values can be
seen by /r_2 /, we consider /hb(w, r_2 )/. (This /happens-before/
ordering does not transitively close with other /happens-before/
orderings.)
Note that the /dereferences/ order is reflexive, and /r_1 / can be the
same as /r_2 /.
For reads of |final| fields, the only writes that are deemed to come
before the read of the |final| field are the ones derived through the
|final| field semantics.
17.5.2. Reading |final| Fields During Construction
A read of a |final| field of an object within the thread that constructs
that object is ordered with respect to the initialization of that field
within the constructor by the usual /happens-before/ rules. If the read
occurs after the field is set in the constructor, it sees the value the
|final| field is assigned, otherwise it sees the default value.
17.5.3. Subsequent Modification of |final| Fields
In some cases, such as deserialization, the system will need to change
the |final| fields of an object after construction. |final| fields can
be changed via reflection and other implementation-dependent means. The
only pattern in which this has reasonable semantics is one in which an
object is constructed and then the |final| fields of the object are
updated. The object should not be made visible to other threads, nor
should the |final| fields be read, until all updates to the |final|
fields of the object are complete. Freezes of a |final| field occur both
at the end of the constructor in which the |final| field is set, and
immediately after each modification of a |final| field via reflection or
other special mechanism.
Even then, there are a number of complications. If a |final| field is
initialized to a compile-time constant expression (ยง15.28
<http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28>) in
the field declaration, changes to the |final| field may not be observed,
since uses of that |final| field are replaced at compile time with the
value of the constant expression.
Another problem is that the specification allows aggressive optimization
of |final| fields. Within a thread, it is permissible to reorder reads
of a |final| field with those modifications of a |final| field that do
not take place in the constructor.
*Example 17.5.3-1. Aggressive Optimization of |final| Fields*
class A {
final int x;
A() {
x = 1;
}
int f() {
return d(this,this);
}
int d(A a1, A a2) {
int i = a1.x;
g(a1);
int j = a2.x;
return j - i;
}
static void g(A a) {
// uses reflection to change a.x to 2
}
}
In the |d| method, the compiler is allowed to reorder the reads of |x|
and the call to |g| freely. Thus, |new A().f()| could return |-1|, |0|,
or |1|.
An implementation may provide a way to execute a block of code in a
/|final|-field-safe context/. If an object is constructed within a
|final|-field-safe context, the reads of a |final| field of that object
will not be reordered with modifications of that |final| field that
occur within that |final|-field-safe context.
A |final|-field-safe context has additional protections. If a thread has
seen an incorrectly published reference to an object that allows the
thread to see the default value of a |final| field, and then, within a
|final|-field-safe context, reads a properly published reference to the
object, it will be guaranteed to see the correct value of the |final|
field. In the formalism, code executed within a |final|-field-safe
context is treated as a separate thread (for the purposes of |final|
field semantics only).
In an implementation, a compiler should not move an access to a |final|
field into or out of a |final|-field-safe context (although it can be
moved around the execution of such a context, so long as the object is
not constructed within that context).
One place where use of a |final|-field-safe context would be appropriate
is in an executor or thread pool. By executing each |Runnable| in a
separate |final|-field-safe context, the executor could guarantee that
incorrect access by one |Runnable| to a object /o/ will not remove
|final| field guarantees for other |Runnable|s handled by the same
executor.
17.5.4. Write-protected Fields
Normally, a field that is |final| and |static| may not be modified.
However, |System.in|, |System.out|, and |System.err| are |static|
|final| fields that, for legacy reasons, must be allowed to be changed
by the methods |System.setIn|, |System.setOut|, and |System.setErr|. We
refer to these fields as being /write-protected/ to distinguish them
from ordinary |final| fields.
The compiler needs to treat these fields differently from other |final|
fields. For example, a read of an ordinary |final| field is "immune" to
synchronization: the barrier involved in a lock or volatile read does
not have to affect what value is read from a |final| field. Since the
value of write-protected fields may be seen to change, synchronization
events should have an effect on them. Therefore, the semantics dictate
that these fields be treated as normal fields that cannot be changed by
user code, unless that user code is in the |System| class.
17.6. Word Tearing
One consideration for implementations of the Java Virtual Machine is
that every field and array element is considered distinct; updates to
one field or element must not interact with reads or updates of any
other field or element. In particular, two threads that update adjacent
elements of a byte array separately must not interfere or interact and
do not need synchronization to ensure sequential consistency.
Some processors do not provide the ability to write to a single byte. It
would be illegal to implement byte array updates on such a processor by
simply reading an entire word, updating the appropriate byte, and then
writing the entire word back to memory. This problem is sometimes known
as /word tearing/, and on processors that cannot easily update a single
byte in isolation some other approach will be required.
*Example 17.6-1. Detection of Word Tearing*
The following program is a test case to detect word tearing:
public class WordTearing extends Thread {
static final int LENGTH = 8;
static final int ITERS = 1000000;
static byte[] counts = new byte[LENGTH];
static Thread[] threads = new Thread[LENGTH];
final int id;
WordTearing(int i) {
id = i;
}
public void run() {
byte v = 0;
for (int i = 0; i< ITERS; i++) {
byte v2 = counts[id];
if (v != v2) {
System.err.println("Word-Tearing found: " +
"counts[" + id + "] = "+ v2 +
", should be " + v);
return;
}
v++;
counts[id] = v;
}
}
public static void main(String[] args) {
for (int i = 0; i< LENGTH; ++i)
(threads[i] = new WordTearing(i)).start();
}
}
This makes the point that bytes must not be overwritten by writes to
adjacent bytes.