我是否正确理解了JSR-133 Cookbook中的Can Reorder规则?

时间:2018-01-31 04:44:28

标签: java multithreading concurrency volatile happens-before

在此链接http://gee.cs.oswego.edu/dl/jmm/cookbook.html中,有一个表格可以说明可以重新排序的内容,而不是。

这是图片

enter image description here

现在看看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教程说这是不可能的。 那么,谁是对的?

2 个答案:

答案 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的读取之上,因为这不会改变程序的功能。