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 中也是“允许的”。
对于这种可能性,我无法理解的文件中的解释是:
编译器可以确定唯一分配给的值
x
是 0 和 42。据此,编译器可以推断出,在我们执行 的点,我们r1 = x
刚刚执行了 42 的写入x
,或者我们刚刚阅读x
并看到值 42。在任何一种情况下,读取值 42 都是合法的x
。然后它可以更改r1 = x
为r1 = 42
; 这将允许更早y = r1
地转换y = 42
和执行,从而导致有问题的行为。在这种情况下,首先提交写入y
。
我的问题是,究竟是什么样的编译器优化?(我对编译器一无所知。)由于 42 只是有条件地编写,当if
满足该语句时,编译器如何决定编写x
?
其次,即使编译器进行了这种推测性的优化,并且提交y = 42
然后最终使r3 = 42
,这是否违反了因果循环,因为现在已经没有因果关系了?
事实上,在同一文档(第 15 页,图 7)中有一个示例,其中提到了类似的因果循环是不可接受的。
那么这个执行顺序为什么在 JMM 中是合法的呢?