【问题标题】:How to understand that "Happens-before consistency is not sufficient" in Java [duplicate]如何理解 Java 中的“Happens-before 一致性是不够的”[重复]
【发布时间】:2014-08-23 06:00:03
【问题描述】:

chapter 17 of Java language specification 中,有一段解释了为什么“在一致性之前发生是不够的”。这是一个例子:

At first,  x = y = 0
Thread 1            | Thread 2
r1 = x;             | r2 = y; 
if (r1 != 0) y = 1; | if (r2 != 0) x = 1;

这是一个可能的执行跟踪:

r1 = x;  // sees write of x = 1
y = 1;
r2 = y;  // sees write of y = 1
x = 1; 

怎么会这样?我感到困惑的是,当第一个动作看到 x = 1 时,这是否意味着条件 r2 != 0 已变为真,因此 y 已分配给 1 ?但是按照这个顺序,y = 1 在 r1 = x 之后。我在哪里弄错了理解这个例子?我应该如何正确解释这个例子?

【问题讨论】:

  • "没有顺序一致的执行"

标签: java concurrency parallel-processing x86 jvm


【解决方案1】:

我相信这个例子在 Java 规范中的观点是 Hans Boehm 等人的观点。写在Outlawing Ghosts,它指出了一些当代语言(Java、C++11,甚至C++14仍然存在,它解决了但没有解决这个问题)的内存模型的缺陷。

重点是:程序按照语言规则正确同步。 (如果在 C++ 中使用原子变量和到处使用memory_order_relaxed,情况也是如此。)但是,仍然不禁止意外行为的发生。套用 Boehm 的话说:机器可以推测 x 的值是 1,然后执行生成的分支,然后(大概是在内存最终响应时)验证 em> 猜测是真的。发现推测确实是真的,因为与此同时另一个线程确实存储了x = 1,机器继续并且不会回滚推测的执行。

更糟糕的是,CPU 真的可以推测 任何 值存在。考虑这个修改后的例子:

r1 = x                     |  r2 = y
if (r1 != 0) y = r1        |  if (r2 != 0) x = r2

在这种情况下,xy 可能以 any 值结束,原因相同。机器可以推测该值是任何东西,然后推测性地继续执行该假设,然后在众所周知的自我实现预言中发现它的推测是正确的。

目前还没有真正的硬件具有这样的行为,这也许是令人放心的。但关键是当代语言的记忆模型并不禁止这种行为。您引用的部分是 Java 试图说的,“看,我们需要发生之前的一致性,但是这里的另一个奇怪的事情仍然不应该发生”。 C++14 在非规范注释 1.10/25 中对这个问题也有同样模糊的看法。

【讨论】:

  • 谢谢@Keerek,由于 CPU 中的分支预测,因此该命令是可能的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-13
相关资源
最近更新 更多