Here:
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.
Are the same guarantees held for the volatile
field?
What if the y
field in the following example would be volatile
could we observe 0
?
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
}
}
}
CodePudding user response:
I think reading 0 is possible.
The spec says:
A write to a volatile variable
v
synchronizes-with all subsequent reads ofv
by any thread (where "subsequent" is defined according to the synchronization order).
In our case, we have a write and a read of the same variable, but there is nothing that ensures the read to be subsequent. In particular, the write and read occur in different threads that are not related by any other synchronization action.
That is, it is possible that the read will occur before the write in synchronization order.
This may sound surprising given that the writing thread writes f
after y
, and the reading thread reads y
only if it detects f
has been written. But since the write and read to f
are not synchronized, the following quote applies:
More specifically, if two actions share a happens-before relationship, they do not necessarily have to appear to have happened in that order to any code with which they do not share a happens-before relationship. Writes in one thread that are in a data race with reads in another thread may, for example, appear to occur out of order to those reads.
The explanatory notes to example 17.4.1 also reaffirm that the runtime is permitted to reorder these writes:
If some execution exhibited this behavior, then we would know that instruction 4 came before instruction 1, which came before instruction 2, which came before instruction 3, which came before instruction 4. This is, on the face of it, absurd.
However, compilers are allowed to reorder the instructions in either thread, when this does not affect the execution of that thread in isolation.
In our case, the behavior of the writing thread, in isolation, is not affected by reordering the writes to f
and y
.
CodePudding user response:
volatile
and initialization are unrelated concepts.
A field's initialization guarantees are unaffected by it being volatile
or not.
See JLS volatile