易失性读取是否发生在易失性写入之前?

我试图理解为什么这个例子是一个正确同步的程序:

a - volatile
Thread1:
x=a
Thread2:
a=5

因为存在冲突的访问(存在写入和读取 a),因此在每个顺序中,一致性执行都必须发生在该访问之间的关系之前。假设顺序执行之一:

1. x=a
2. a=5

1 发生在 2 之前,为什么?


答案 1

1 发生在 2 之前,为什么?

我不是100%确定我理解你的问题。

如果您有一个易失性变量,并且一个线程正在从中读取,另一个线程正在写入该变量,则这些访问的顺序可以按任一顺序排列。这是一个竞态条件。JVM 和 Java 内存模型 (JMM) 所保证的内容取决于哪个操作首先发生。a

写入可能刚刚发生,读取看到更新的值。或者写入可能发生在读取之后。因此,可以是 或 以前的值。x5a

每个顺序一致性执行都必须发生在访问之间的关系之前

我不确定这意味着什么,所以我会尽量具体一些。“在关系之前发生”意味着在读取同一变量之前,所有先前对变量的内存写入都保证已完成。但是,这种保证绝不能解释受争用条件约束的两个操作之间的时间。读者可以保证已经看到了写入,但前提是写入发生在读取之前。volatilevolatilevolatile

您可能认为这是一个非常弱的保证,但是在使用本地CPU缓存显着提高性能的线程中,读取字段的值可能来自缓存的内存段而不是中央内存。该保证对于确保本地线程内存在读取发生时失效和更新至关重要,以便线程可以适当地共享数据。volatile

同样,JVM 和 JMM 保证,如果您正在从字段读取 ,那么在读取之前对同一字段的任何写入都将被它看到 - 写入的值将被正确发布并且对读取线程可见。但是,此保证绝不决定顺序。它没有说写入必须在读取之前进行。volatilea


答案 2

不可以,在(按同步顺序)对同一变量进行易失性写入之前(按同步顺序)不一定会发生易失性读取- 在易失性写入之前。

这意味着它们可能处于“数据竞赛”中,因为它们是“冲突的访问,而不是按发生前关系排序的”。如果这是真的,几乎所有程序都包含数据竞赛:)但这可能是一个规范错误。易失性读取和写入永远不应被视为数据争用。如果程序中的所有变量都是易失性的,则所有执行都是平凡的顺序一致的。查看 http://cs.oswego.edu/pipermail/concurrency-interest/2012-January/008927.html