在此链接http://gee.cs.oswego.edu/dl/jmm/cookbook.html中,有一张表说明了哪些可以重新排序,哪些不能。
这是图像
现在看看来自http://tutorials.jenkov.com/java-concurrency/volatile.html的这句话
“之前和之后的指令可以重新排序,但易失性读或写不能与这些指令混合。”
所以例如说我有代码
int x = 5;
int z = 2; // storing 2 into z
z = someVolatileIntNotTwo; // storing some volatile int that != 2 into z
int a = 6;
System.out.println(z);
从表格告诉我的内容来看,可以重新排序普通存储和可变负载,这意味着
int z = 2; // storing 2 into z
z = someVolatileIntNotTwo; // storing some volatile int that != 2 into z
可以重新排序为
z = someVolatileIntNotTwo; // storing some volatile int that != 2 into z
int z = 2; // storing 2 into z
这可能意味着程序将在重新排序的情况下打印 2 以外的内容。
这背后的原因是首先 z = 2 进行正常存储,然后 z = someVolatileIntNotTwo 进行易失性加载,然后进行正常存储。虽然不能重新排序后跟普通存储的易失性加载,但在这种情况下不会发生这种情况,因为如果重新排序,我们仍然会得到这个序列。
z = someVolatileIntNotTwo; // volatile Load then normal Store.
int z = 2; // normal load
除了正常加载(int z = 2)和[易失性加载和正常存储](z = someVolatileIntNotTwo)被重新排序之外,第一个操作与第二个操作重新排序,根据表格很好
但是,詹科夫教程说这是不可能的。那么,谁是对的?