以下来自经典Concurency in Practice
:
当线程 A 写入 volatile 变量并且随后线程 B 读取相同的变量时,在写入 volatile 变量之前对 A 可见 的所有变量的值在读取 volatile 变量后对 B 可见。
我不确定我是否能真正理解这句话。例如,在这种情况下所有变量的含义是什么?这是否意味着 usingvolatile
对非易失性变量的使用也有副作用?
在我看来,这句话有一些我无法理解的微妙含义。
有什么帮助吗?
以下来自经典Concurency in Practice
:
当线程 A 写入 volatile 变量并且随后线程 B 读取相同的变量时,在写入 volatile 变量之前对 A 可见 的所有变量的值在读取 volatile 变量后对 B 可见。
我不确定我是否能真正理解这句话。例如,在这种情况下所有变量的含义是什么?这是否意味着 usingvolatile
对非易失性变量的使用也有副作用?
在我看来,这句话有一些我无法理解的微妙含义。
有什么帮助吗?
您的问题的答案在JLS #17.4.5中:
对 volatile 字段(第 8.3.1.4 节)的写入发生在对该字段的每次后续读取之前。
所以如果在一个线程中你有
aNonVolatileVariable = 2 //w1
aVolatileVariable = 5 //w2
随后在另一个线程中:
someVariable = aVolatileVariable //r1
anotherOne = aNonVolatileVariable //r2
anotherOne
即使该变量不是易失性的,您也可以保证等于 2。所以是的,使用 volatile 对使用非易失性变量也有副作用。
更详细地说,这是由于 Java 内存模型 (JMM) 在同一部分中提供的另外两个保证:线程内顺序和传递性(hb(x,y)表示x 发生在 y 之前):
如果 x 和 y 是同一线程的操作,并且 x 在程序顺序中位于 y 之前,则为 hb(x, y)。
[...]
如果hb(x, y)和hb(y, z),那么hb(x, z)。
在我的例子中:
所以你可以通过传递性得出hb(w1, r2)的结论。
并且 JMM 保证程序的所有执行将是顺序一致的(即看起来好像没有重新排序),如果它与发生前的关系正确同步。所以在这种特定情况下,非易失性读取保证看到非易失性写入的效果。
这意味着如果您写入十个非易失性变量并写入一个易失性变量,则必须在易失性变量之前设置所有非易失性变量。
如果您阅读 volatile 变量和所有非易失性变量,您可以确定订单不会被交换。