Java规范:读取-查看执行顺序中稍后发生的写入

Java规范:读取-查看执行顺序中稍后发生的写入,java,jvm,memory-model,language-specifications,Java,Jvm,Memory Model,Language Specifications,我现在正在阅读Java语言规范 说 在该执行中,读操作将看到执行顺序中稍后发生的写操作。这似乎有悖常理,但在一致性发生之前是允许的。允许读取看到以后的写入有时会产生不可接受的行为 说 虽然允许读操作看到执行顺序后面的写操作有时是不可取的,但有时也是必要的 17.4.8-1也给出了一个奇怪的例子 为什么读看到写以后会出现可能 如果真的有可能,我如何在java代码中重现它 编辑 这不是重复的问题。这个问题刚刚问了17.4.5-1,我能理解17.4.5-1,因为编译器可能会对它们重新排序。但是17.4

我现在正在阅读Java语言规范

在该执行中,读操作将看到执行顺序中稍后发生的写操作。这似乎有悖常理,但在一致性发生之前是允许的。允许读取看到以后的写入有时会产生不可接受的行为

虽然允许读操作看到执行顺序后面的写操作有时是不可取的,但有时也是必要的

17.4.8-1也给出了一个奇怪的例子

为什么
读看到写以后会出现
可能

如果真的有可能,我如何在java代码中重现它

编辑
这不是重复的问题。这个问题刚刚问了17.4.5-1,我能理解17.4.5-1,因为编译器可能会对它们重新排序。但是17.4.8-1呢?它在执行和因果关系要求下。根据
执行顺序的定义
,任何人都不能重新排序

r1 = x; // write

因此,
y=1
必须在最后发生。

示例

在具有推测性执行的体系结构上是可能的。因此,当从主存请求的值尚未到达时,CPU遇到条件分支,并决定执行条件代码,并在条件未满足时回滚

当值到达CPU内核时,它是由另一个线程写入的值,因此满足条件并保留更改


您不能在Java代码中重现这种情况,因为规范继续解释Java代码不允许出现这种情况。这是一个被允许的例子,如果我们只在一致性之前发生。但Java还禁止“凭空值”。因此,支持这种推测性执行的架构的JVM实现必须确保它仅限于其他线程看不到的变量(或完全禁用它)。

据我所知,这并不是说在这种情况下可能出现竞争条件。这是说,仅仅发生在之前不足以保证正确性,因此需要因果关系要求。JIT甚至CPU可以为了优化而重新排序指令。这可能意味着首先执行的读取可以看到稍后执行的写入。这是非常罕见的,一种更常见的行为是懒散,在这种情况下,读操作在写入内存后会看到一个旧值。注意:对于常规Java代码,这种情况永远不会发生,因此我不确定它是否与JLS相关。@PeterLawrey但17.4.8-1示例无法通过重新排序来解释。@shmosel您可能是对的。这只是理论上的一个悖论。这就是为什么我找不到任何可运行的例子。“这不是重复的问题。那个问题刚刚问过……”:为了清楚起见,添加一个“那个问题”的链接。
if (r1 != 0) // read
Table 17.4.8-A

      Thread 1                  Thread 2
r1 = x;                    r2 = y;
if (r1 != 0) y = 1;        if (r2 != 0) x = 1;