Let's see this simple Java program:
import java.util.*;
class A {
static B b;
static class B {
int x;
B(int x) {
this.x = x;
}
}
public static void main(String[] args) {
new Thread() {
void f(B q) {
int x = q.x;
if (x != 1) {
System.out.println(x);
System.exit(1);
}
}
@Override
public void run() {
while (b == null);
while (true) f(b);
}
}.start();
for (int x = 0;;x++)
b = new B(Math.max(x%2,1));
}
}
Main thread
The main thread creates an instance of B
with x
set to 1, then writes that instance to the static field A.b
. It repeats this action forever.
Polling thread
The spawned thread polls until it finds that A.b.x
is not 1.
?!?
Half the time it goes in an infinite loop as expected, but half the time I get this output:
$ java A
0
Why is the polling thread able to see a B
that has x
not set to 1?
x%2
instead of just x
is here simply because the issue is reproducible with it.
I'm running openjdk 6 on linux x64.
Here is what I think: because b is not final, the compiler is free to reorder the operations as it likes, right? So this, fundamentally is a reordering issue and as a result a unsafe publication issue Marking the variable as final will fix the problem.
More or less, it is the same example as provided here in the Java memory model docs.
The real question is how is this possible. I can also speculate here (since I have no idea how the compiler will reorder), but maybe the reference to B is written to the main memory (where it is visible to the other thread) BEFORE the write to x happens. In between these two operations the read happens, thus the zero value
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With