易变量和其他变量

时间:2012-09-15 15:05:52

标签: java multithreading concurrency volatile memory-visibility

以下内容来自经典Concurency in Practice

  

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

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

2 个答案:

答案 0 :(得分:13)

您的问题的答案位于JLS #17.4.5

  

在对该字段的每次后续读取之前发生对易失性字段(第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,w2) hb(r1,r2)(内部线程语义)
  • 由于易变保证
  • hb(w2,r1)

所以你可以通过传递性来得出 hb(w1,r2)

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

答案 1 :(得分:8)

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

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