在此链接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)和[volatile volatile and normal store](z = someVolatileIntNotTwo)重新排序之外,没有第一个操作被重新排序的情况,根据表格很好
然而,jenkov教程说这是不可能的。 那么,谁是对的?
答案 0 :(得分:2)
您对重新排序范围的解释过于宽泛。来自JSR-133 Cookbook:
即使表没有这样说,也无法将后续商店的负载重新排序到同一位置。
更直接地回答您的问题:两篇文章都不正确。您的样本中的重新排序是非法的。
答案 1 :(得分:2)
重新排序只有在发出的重新排序维护程序顺序时才会发生,就好像单个线程正在执行一样。这意味着,JVM无法通过重新排序来更改应用程序的结果。所以在你的情况下,这不是一个合法的重新排序。
如果我举个例子
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 a = 6;
int x = 5;
int z = 2; // storing 2 into z
z = someVolatileIntNotTwo; // storing some volatile int that != 2 into z
System.out.println(z);
将a
的分配移到someVolatileIntNotTwo
的读取之上,因为这不会改变程序的功能。