易变量和其他变量

Cra*_*lus 14 java concurrency multithreading volatile memory-visibility

以下是经典Concurency in Practice:

当线程A写入volatile变量并且随后线程B读取相同的变量时,在写入volatile变量之前A可见的所有变量的值在读取volatile变量后变为B可见.

我不确定我是否真的能理解这句话.例如,在这种情况下所有变量的含义是什么?这是否意味着使用volatile也会对非易失性变量的使用产生副作用?
在我看来,这句话有一些我无法理解的微妙含义.
有帮助吗?

ass*_*ias 14

您的问题的答案在JLS#17.4.5中:

写入易失性字段(第8.3.1.4节) - 在每次后续读取该字段之前发生.

所以,如果你在一个线程中

aNonVolatileVariable = 2 //w1
aVolatileVariable = 5 //w2
Run Code Online (Sandbox Code Playgroud)

然后在另一个线程中:

someVariable = aVolatileVariable //r1
anotherOne = aNonVolatileVariable //r2
Run Code Online (Sandbox Code Playgroud)

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,w2)hb(r1,r2)(内部线程语义)
  • hb(w2,r1)因为波动性保证

所以你可以通过传递性得出hb(w1,r2)的结论.

并且JMM保证程序的所有执行都是顺序一致的(即看起来没有任何重新排序)如果它与之前发生的关系正确同步.因此,在这种特定情况下,保证非易失性读取能够看到非易失性写入的效果.


Pet*_*rey 9

这意味着如果您写入十个非易失性变量并写入易失性变量,则必须在易失性变量之前设置所有非易失性变量.

如果您读取volatile变量和所有非易失性变量,您可以确保不会交换订单.

  • 在易失性变量中设置的值的顺序不能相对于其他变量(易失性或其他)更改,但是对于非易失性变量可能会发生这种情况。这意味着,当您设置易失性变量时,所有先前设置的值即使不是易失性的,也会被设置为缓存连贯的。 (2认同)