如何理解"发生 - 在一致性之前是不够的"在Java中

时间:2014-08-23 06:00:03

标签: java concurrency parallel-processing x86 jvm

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?但按顺序,在r1 = x之后,y = 1。我在哪里弄错了理解这个例子?我该如何正确理解这个例子?

1 个答案:

答案 0 :(得分:6)

我相信这个例子在Java规范中提出的观点是Hans Boehm等人的观点。在Outlawing Ghosts中写一下,它指出了某些当代语言(Java,C ++ 11,甚至是C ++ 14)的内存模型的不足,但它们已解决但未解决此问题。 / p>

重点在于:编写的程序通过语言规则正确同步。 (如果你在任何地方都使用原子变量和memory_order_relaxed,那么在C ++中也是如此。)但是,仍然不禁止发生意外行为。用Boehm来解释:机器可以推测的值,例如x为1,然后执行结果分支​​,稍后(大概是当内存最终响应时)验证猜测是真的。确实找到了猜测,因为在此期间另一个线程确实存储了x = 1,机器继续并且不会回滚推测的执行。

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

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

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

或许可以放心,目前没有真正的硬件表现得像这样。但重点是当代语言的记忆模型并不禁止这种行为。你引用的部分是Java试图说,“看,我们需要发生 - 之前的一致性,但这里的另一个奇怪的事情仍然不应该发生”。在非规范性说明1.10 / 25中,C ++ 14对此问题的看法同样含糊不清。