I modified one of JCStress examples:
@JCStressTest
@Outcome(id = "0, 0", expect = ACCEPTABLE, desc = "Doing both reads early.")
@Outcome(id = "1, 1", expect = ACCEPTABLE, desc = "Doing both reads late.")
@Outcome(id = "1, 0", expect = ACCEPTABLE, desc = "First is visible but not second.")
@Outcome(id = "0, 1", expect = ACCEPTABLE_INTERESTING, desc = "Second is visible but not first.")
@State
public class Reordering {
int first;
int second;
@Actor
public void actor1() {
first = 1;
second = 1;
}
@Actor
public void actor2(II_Result r) {
r.r2 = second;
r.r1 = first;
}
}
which gave me the following result:
RESULT | SAMPLES | FREQ | EXPECT | DESCRIPTION |
---|---|---|---|---|
0, 0 | 737,822,067 | 26.75% | Acceptable | Doing both reads early. |
0, 1 | 1,838,578 | 0.07% | Interesting | Second is visible but not first. |
1, 0 | 13,081,701 | 0.47% | Acceptable | First is visible but not second. |
1, 1 | 2,005,604,406 | 72.71% | Acceptable | Doing both reads late. |
The Acceptable results are easy to understand but I have some questions regarding the Interesting outcome. From what I understood, JVM can optimize the code and change the order of instructions meaning the first function could roughly be translated to:
public void actor1() {
second = 1;
first = 1;
}
which could explain why the Interesting result was achieved. My question is: is it possible that the Interesting result was achieved not due to the code reordering done by JVM but rather by "caching" the first
and not making it visible to the thread running actor2
method since the field was not a volatile one? By caching I am talking about storing it in the CPU register/store buffer and making it not visible to the other thread.