1

在此链接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)被重新排序之外,第一个操作与第二个操作重新排序,根据表格很好

但是,詹科夫教程说这是不可能的。那么,谁是对的?

4

2 回答 2

2

您对重新排序范围的解释过于宽泛。来自 JSR-133 食谱:

即使表格没有这样说,您也无法将后续存储的负载重新排序到同一位置。

更直接地回答您的问题:两篇文章都不正确。您的样品中的重新排序是非法的。

于 2018-01-31T19:09:46.750 回答
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因为这不会改变程序的功能。

于 2018-01-31T19:23:16.820 回答