在阅读this blog post时,我没有理解第3.6和3.7节。
3.6中的代码:
@JCStressTest
@State
public class AcquireOrderWrong {
int x;
volatile int g;
@Actor
public void actor1() {
g = 1;
x = 1;
}
@Actor
public void actor2(IntResult2 r) {
r.r1 = x;
r.r2 = g;
}
}
3.7中的代码:
@JCStressTest
@Outcome(id = "1, 0", expect = Expect.FORBIDDEN, desc = "Happens-before violation")
@Outcome( expect = Expect.ACCEPTABLE, desc = "All other cases are acceptable.")
@State
public class SafePublication {
int x;
volatile int ready;
@Actor
public void actor1() {
x = 1;
ready = 1;
}
@Actor
public void actor2(IntResult2 r) {
r.r1 = ready;
r.r2 = x;
}
}
在3.6中,由于它是一个赤裸裸的数据竞赛,因此我认为1,0是一个不可能的结果我可能错误地将其解释为,因为不相关的操作可能是在执行时重新排序,这可能会发生。
但如果是这种情况,那么3.7中的例子不应该遭遇同样的问题吗?
答案 0 :(得分:2)
在3.7中,ready
是一个volatile
变量,根据doc
这意味着对volatile变量的更改始终可见 其他线程。更重要的是,它还意味着当线程读取时 volatile变量,它不仅看到了volatile的最新变化, 但也导致了改变的代码的副作用。
在actor()
中,您在设置ready
后设置x
。因此,当您在方法ready
中阅读actor2
时,JVM可以保证x=1
也可见,从而避免(1, 0)
作为输出。