This post was raised after reading: https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/#pitfall-semi-sync
class Box {
int x;
public Box(int v) {
x = v;
}
}
class RacyBoxy {
Box box;
public synchronized void set(Box v) {
box = v;
}
public Box get() {
return box;
}
}
and test:
@JCStressTest
@State
public class SynchronizedPublish {
RacyBoxy boxie = new RacyBoxy();
@Actor
void actor() {
boxie.set(new Box(42)); // set is synchronized
}
@Actor
void observer(IntResult1 r) {
Box t = boxie.get(); // get is not synchronized
if (t != null) {
r.r1 = t.x;
} else {
r.r1 = -1;
}
}
}
The author says that it is possible that r.r1 == 0
. And I agree with
that. But, I am confused with an explanation:
The actual failure comes from the fact that reading a reference to an object and reading the object’s fields are distinct under the memory model.
I agree that
reading a reference to an object and reading the object’s fields are distinct under the memory model but, I don't see how it has an influence on result.
Please help me understand it.
P.S. If someone is confused about @Actor
. It just means: run in a thread.
I think it adresses a common miconception of people that read code with regards to sequential consitency. The fact that the reference to an instance is available in one thread, does not imply that its constructor is set. In other words: reading an instance is a different operation than reading an instance's field. Many people assume that once they can observe an instance, it requires the constructor to be run but due to the missing read synchronization, this is not true for the above example.