Java 内存模型:易失性变量和发生前

我想澄清一下发生之前的关系如何处理可变变量。让我们有以下变量:

public static int i, iDst, vDst;
public static volatile int v;

和线程 A:

i = 1;
v = 2;

和线程 B:

vDst = v;
iDst = i;

根据 Java 内存模型 (JMM),以下语句是否正确?如果不是,什么是正确的解释?

  • i = 1总是发生在之前 v = 2
  • v = 2 在 JMM 中发生之前,仅当它实际发生之前时才发生vDst = v
  • i = 1 在 JMM 中发生之前(并且将被可预测地分配),如果实际发生之前在时间上iDst = iiDst1v = 2vDst = v
  • 否则,和 之间的顺序未定义,并且 的结果值也未定义i = 1iDst = iiDst

逻辑错误:

JMM中没有“挂钟时间”的概念,我们应该依靠同步顺序作为和的排序指南。有关更多详细信息,请参阅所选答案。v = 2vDst = v


答案 1
  • i = 1总是发生在之前 v = 2

真。根据 JLS 第 17.4.5 节

如果 xy 是同一线程的操作,并且 x 在程序顺序中位于 y 之前,则 hb(x, y)。


  • v = 2 在 JMM 中发生之前,仅当它实际发生之前时才发生vDst = v
  • i = 1 在 JMM 中发生之前(并且将被可预测地分配),如果实际发生之前在时间上iDst = iiDst1v = 2vDst = v

假。“事前必争”的顺序并不能保证在物理时间上彼此之前发生的事情。从JLS的同一部分,

应该注意的是,两个操作之间存在“发生之前”关系并不一定意味着它们在实现中必须按该顺序发生。如果重新排序产生与合法执行一致的结果,则不违法。

但是,可以保证在同步顺序中发生之前之前发生,如果之前发生,则在执行的同步操作上的总顺序,通常被误认为是实时顺序。v = 2vDst = vi = 1iDst = iv = 2vDst = v


  • 否则,和 之间的顺序未定义,并且 的结果值也未定义i = 1iDst = iiDst

如果以同步顺序出现在前面,则会出现这种情况,但实际时间不会进入同步顺序。vDst = vv = 2


答案 2

是的,根据本节关于发生之前的顺序,它们都是正确的

  1. i = 1总是发生在之前,因为:v = 2

如果 x 和 y 是同一线程的操作,并且 x 在程序顺序中位于 y 之前,则 hb(x, y)。

  1. v = 2 在JMM中发生之前,只有当它实际上发生在时间之前,因为它是不稳定的,并且vDst = vv

对易失性字段 (§8.3.1.4) 的写入发生在每次后续读取该字段之前。

  1. i = 1 在 JMM 中发生之前发生(并且将可预测地分配 1),如果实际发生在时间之前。这是因为在这种情况下:iDst = iiDstv = 2vDst = v
    • i = 1 发生之前 v = 2
    • v = 2 发生之前 vDst = v
    • vDst = v 发生之前 iDst = i

如果 hb(x, y)hb(y, z),则 hb(x, z)

编辑:

正如@user2357112所说,陈述2和3似乎不准确。发生之前关系不一定在具有这种关系的操作之间施加计时顺序,如JLS的同一部分所述:

应该注意的是,两个操作之间存在“发生之前”关系并不一定意味着它们在实现中必须按该顺序发生。如果重新排序产生与合法执行一致的结果,则不违法。

因此,就JLS中提到的规则而言,我们不应该对语句执行的实际时间做出假设。


推荐