gpt4 book ai didi

java - 为什么在 Java 内存模型中允许这种行为?

转载 作者:太空狗 更新时间:2023-10-29 22:47:26 25 4
gpt4 key购买 nike

JMM 中的因果关系似乎是其中最令人困惑的部分。我有几个关于 JMM 因果关系和并发程序中允许的行为的问题。

据我了解,当前的 JMM 始终禁止因果循环。 (我说得对吗?)

现在,根据 JSR-133文档,第 24 页,图 16,我们有一个示例,其中:

最初x = y = 0

线程 1:

r3 = x;
if (r3 == 0)
x = 42;
r1 = x;
y = r1;

线程 2:

r2 = y;
x = r2;

直觉上,r1 = r2 = r3 = 42 似乎是不可能的。然而,它不仅被提及为可能,而且在 JMM 中也被“允许”。

对于这种可能性,文档中我看不懂的解释是:

A compiler could determine that the only values ever assigned to x are 0 and 42. From that, the compiler could deduce that, at the point where we execute r1 = x, either we had just performed a write of 42 to x, or we had just read x and seen the value 42. In either case, it would be legal for a read of x to see the value 42. It could then change r1 = x to r1 = 42; this would allow y = r1 to be transformed to y = 42 and performed earlier, resulting in the behavior in question. In this case, the write to y is committed first.

我的问题是,它到底是一种什么样的编译器优化? (我对编译器一无所知。)由于 42 只是有条件地写入,当满足 if 语句时,编译器如何决定是否继续写入 x

其次,即使编译器进行了这种推测性优化,并提交了 y = 42 和然后最终使 r3 = 42 ,这不是违反因果循环吗,因为现在没有因果区别了?

事实上,在同一文档(第 15 页,图 7)中有一个示例,其中提到类似的因果循环是 Not Acceptable 。

那么为什么这个执行顺序在 JMM 中是合法的呢?

最佳答案

正如所解释的,曾经写入x 的唯一值是 0 和 42。线程 1:

r3 = x; // here we read either 0 or 42
if (r3 == 0)
x = 42;
// at this point x is definitely 42
r1 = x;

因此 JIT 编译器可以将 r1 = x 重写为 r1 = 42,进而 y = 42。重点是,线程 1 将总是、无条件地将 42 写入 yr3 变量实际上是多余的,可以从机器代码中完全删除。所以例子中的代码只是给出了从xy的因果箭头的表象,但仔分割析发现,实际上并没有因果关系。令人惊讶的结果是可以提前提交对 y 的写入。

关于优化的一般说明:我认为您熟悉从主内存读取所涉及的性能损失。这就是 JIT 编译器一心想尽可能拒绝这样做的原因,在这个例子中,事实证明它实际上不需要读取 x 来知道要写入什么 y

关于符号的一般说明:r1r2r3局部变量(它们可以在堆栈或 CPU 寄存器中); x, y共享变量(这些在主内存中)。如果不考虑这一点,示例将毫无意义。

关于java - 为什么在 Java 内存模型中允许这种行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13271649/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com