I recently stumbled upon this example in jcstress:
@JCStressTest
@State
@Outcome(id = "10", expect = ACCEPTABLE, desc = "Boring")
@Outcome(id = {"0", "1"}, expect = FORBIDDEN, desc = "Boring")
@Outcome(id = {"9", "8", "7", "6", "5"}, expect = ACCEPTABLE, desc = "Okay")
@Outcome( expect = ACCEPTABLE_INTERESTING, desc = "Whoa")
public static class Volatiles {
volatile int x;
@Actor
void actor1() {
for (int i = 0; i < 5; i++) {
x++;
}
}
@Actor
void actor2() {
for (int i = 0; i < 5; i++) {
x++;
}
}
@Arbiter
public void arbiter(I_Result r) {
r.r1 = x;
}
}
The author highlights that since increments are not atomic operations one cannot expect to just "lose" one increment update per loop iteration. So then all outcomes (up to 10) except 0 and 1 are allowed (and indeed happen).
I see why 0 is not allowed: there is an HB edge between the initialization of default values of objects and the first action in every thread as stated in JLS.
JLS 17.4.4
The write of the default value (zero, false, or null) to each variable synchronizes-with the first action in every thread.
The author also explains how one might get the result 2:
The most interesting result, "2" can be explained by this interleaving:
Thread 1: (0 ------ stalled -------> 1) (1->2)(2->3)(3->4)(4->5)
Thread 2: (0->1)(1->2)(2->3)(3->4) (1 -------- stalled ---------> 2)
I understand that you cannot just "extend" the explanation above like this:
Thread 1: (0 --------- stalled -----------> 1) (1->2)(2->3)(3->4)(4->5)
Thread 2: (0->1)(1->2)(2->3)(3->4)(4->5)
Because it leads to the result 5.
But isn't there an execution that will produce 1?
I definitely can't think of any. But why there actually is none?