我正在观看来自java jpoint会议的视频。
我对来自Alexey Shipilev报告的幻灯片提出了疑问:
对不起幻灯片上的非英语。实际上作者说变量集不可能是
r1 = 1 (Y)
r2 = 0 (x)
r3 = 1 (x)
r4 = 0 (Y)
根据视频,他暗示这显然是。
根据JMM,有人可以澄清为什么这个值设定不可能吗?
P.S。
如果我理解Alexey符号正确,则尊重以下代码:
public class SequentialConsistency {
static volatile int x;
static volatile int y;
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
x = 1;
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
y = 1;
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("r1=" + x + ", r2=" + y);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("r3=" + x + ", r4=" + y);
}
}).start();
}
}
答案 0 :(得分:2)
相信我理解。
让我们说我们有4个帖子。 t1-t4(根据图片从左到右)
t3 读取 y 然后 x ,我们看到结果
y=1
x=0
这意味着序列如下:
这是唯一可行的序列。
让我们检查 t4 读数:
x=1
y=0
根据t3的推理,这意味着
t2 write
发生在t1 write
之前,但它与 t3 输出相矛盾,因此不可能
答案 1 :(得分:2)
您可以为此代码构建详尽的SC执行列表,并且不会实现SC执行产生(1,0,1,0)。
模型方面,很容易争论。同步顺序(SO)一致性表示同步读取应该在SO中看到最后一次同步写入。 SO-PO一致性表示SO应该与程序顺序一致。
这允许通过矛盾来描绘证明。假设存在产生(1,0,1,0)的执行。然后,在那些执行中,由于SO的一致性,所以看到零必须按此顺序:
(r2 = x):0 --so--> (x = 1) [1]
(r4 = y):0 --so--> (y = 1) [2]
...并且其他两个读取必须按此顺序进行写入以查看它们(由于SO一致性):
(x = 1) --so--> (r3 = x):1 [3]
(y = 1) --so--> (r1 = y):1 [4]
......而且,由于SO-PO的一致性:
(r1 = y):1 --po--> (r2 = x):0 [5]
(r3 = x):1 --po--> (r4 = y):0 [6]
这产生了奇怪的传递性SO,它是循环的:
(r2 = x):0 --so--> (r3 = x):1 --so--> (r4 = y):0 --so--> (r1 = y):1 --so--> (r2 = x):0
[1,3] [6] [2,4] [5]
请注意,对于上面执行中的任何一对动作A!= B,我们可以说(A --so--> B)
和(B --so--> A)
- 这称为对称性。根据定义,SO是总顺序,总顺序是反对称,这里我们有对称的。我们已经陷入矛盾,因此不存在这样的执行。 Q.E.D。
答案 2 :(得分:0)
您可以用稍微简单的形式来考虑它(尽管您无法得到比Aleksey所说的更正确的东西)。 Java中的volatile
提供了sequential consistency
,这意味着操作以全局和原子顺序 like 完成。如果您写入字段(x = 1
),则每个人都会看到该写入。根据您的示例,使其更正确,如果有一个ThreadA
执行x = 1
,则ThreadB
(执行r2 = x
)和ThreadC
(即r3 = x
),将读取x
为1
。这就是顺序一致性的保证。
幻灯片显示,在SC
(顺序一致)中执行:1, 0, 1, 0
是不可能的。因为那意味着:
ThreadA wrote to x value of 1
ThreadB observed that value to be 1 (via r2 = x)
ThreadC observed that value to be 0 (via r3 = x)
但是在SC世界中,一旦发生写操作(并且我们知道发生这种情况是因为ThreadB
已经观察到了),那么其他所有人都必须观察到它。这里不是这种情况:ThreadC
看到x
是0
。因此,这会破坏SC。
您必须回想起他的观点是-“我们可以用发布/获取来替换所有易失性吗?(毕竟便宜)。”答案是否定的,因为SC 禁止 1, 0, 1, 0
,而release/acquire
允许。