Let's say we have a class
class Foo {
int x;
Foo() {
x = 5;
}
}
and some client code
public static void main(String[] args) {
Foo foo = new Foo();
new Thread(() -> {
while (true) {
new Thread(() -> {
if (foo.x != 5) {
throw new AssertionError("this statement is false 1");
}
new Thread(() -> {
if (foo.x != 5) {
throw new AssertionError("this statement is false 2");
}
}).start();
}).start();
}
}).start();
}
Is it impossible for an AssertionError to be thrown because happens-before is transitive?
Even though Foo's x is not final, because of the happens-before guarantee of Thread.start(), a newly created thread from the thread that instantiated Foo, will see all the updates up to having called Thread.Start().
However, this thread also spawns many children threads, and since there is a happens-before relationship again, can we say that because of the transitive property of the happens-before, that AssertionError could never be thrown?
Your question:
The answer is yes. As we can see in the JLS8 section 17.4.5. Happens-before Order:
It is also given in the same section of the JLS that:
So there is
new Foo()
, first-action-in-first-thread) andwhich means that there is also:
new Foo()
, first-action-in-first-assertion-thread)new Foo()
, first-action-in-second-assertion-thread)(Since "For each thread t, the synchronization order of the synchronization actions (§17.4.2) in t is consistent with the program order (§17.4.3) of t.", I can omit the steps in-between, like the
while(true)
loop)