Java内存模型重排:JCStress测试未出现(1,0)结果的原因探究
为什么JCStress测试中从未出现(1,0)的结果?
先看你的测试代码:
@JCStressTest @Outcome(id = "1, 1", expect = Expect.ACCEPTABLE, desc = "ordered") @Outcome(id = "0, 1", expect = Expect.ACCEPTABLE, desc = "ordered") @Outcome(id = "1, 0", expect = Expect.ACCEPTABLE, desc = "reordered") @Outcome(id = "0, 0", expect = Expect.ACCEPTABLE, desc = "ordered") @State public class TestJUC { private int x; public TestJUC() {} @Actor public void actor1() { x = 1; } @Actor public void actor2(II_Result r) { int a = x; r.r1 = a; int b = x; r.r2 = b; } }
你提到理论上actor2的语句可以重排成先读b再读a,进而产生(1,0)的结果,但实际测不出来,核心原因是你大概率在x86架构的机器上跑测试,而x86的内存模型不允许这种重排:
- x86采用TSO(全存储顺序)内存模型,对内存操作的重排有硬限制:读操作不能被重排到更早的读操作前面,也就是actor2里两次读
x的顺序必须和代码编写顺序一致——先读a,再读b。 - 这样一来,只会出现三种结果:
- actor1完全未执行:两次读
x都得到0,结果为(0,0); - actor1在actor2读
a之后、读b之前执行:a为0,b为1,结果为(0,1); - actor1在actor2开始前就执行完毕:两次读
x都得到1,结果为(1,1)。
- actor1完全未执行:两次读
- 你设想的先读
b(读到0)、再让actor1写x=1、最后读a(读到1)的场景,在x86架构下根本不可能发生,因为处理器不会重排这两个读操作的顺序。
如果换用ARM、PowerPC这类弱内存模型的架构运行测试,确实有可能观测到(1,0)的结果——这些架构允许更多内存操作重排。
内容的提问来源于stack exchange,提问作者qwee
相关产品推荐
相关产品推荐

