引擎盖下的java中的易失性关键字

时间:2017-03-14 09:49:04

标签: java multithreading volatile

我和老师讨论过java中的volatile关键字。 当变量被声明为volatile

时,是否正确
  

此变量的值永远不会缓存在线程本地:all   读取和写入将直接进入"主存["。

我的老师的意见是:

  

volatile关键字承诺变量的值   保存在主存中。

有人可以解决我们的冲突吗?谢谢!

4 个答案:

答案 0 :(得分:9)

关于volatile等关键字的确切含义,请查看Java语言规范以查看官方含义。

JLS paragraph 8.3.1.4解释了volatile的含义:

  

字段可以声明为volatile,在这种情况下,Java Memory Model可以确保所有线程都看到变量的一致值(第17.4节)。

Paragraph 17.4解释了Java内存模型。内存模型为程序中每个语句后的数据发生了什么保证。

如果你仔细研究,你会发现volatile意味着如果你写一个volatile变量,你可以保证其他线程会看到写的内容。故意没有具体说明如何在实践中实施。它可以通过强制写入主内存来实现,但JVM实现者可以自由选择不同的,可能更有效的机制。

所以,严格来说,你的老师是对的。它并不一定意味着将值写入主存储器;虽然在实践中可能就是这种情况 - 但这取决于特定的JVM实现。

答案 1 :(得分:1)

volatile做的是忽略所有本地CPU缓存;或者等效地刷新包含要从主存储器刷新的volatile变量的缓存行。因此,正如文档所示,它确保所有读取都直接从主存储器读取,并且所有写入都直接进入主存储器。

除此之外,volatile还具有原子操作保证。它确保以此关键字为前缀的变量将被完整地读取或写入,就像它是单个指令一样。 (相比之下,你不会担心由2个线程写入的64位长整数最后是来自一个线程的第一个32位和来自另一个线程的第二个32位。)因此在某些情况下,例如如果在32位机器上对64位长整数使用volatile,则JVM可能需要做的不仅仅是“易失性”指令。还有一些文件位于https://blogs.oracle.com/dave/entry/java_memory_model_concerns_on

针对您的具体问题。

  • 在Java中读取volatile时,它确保变量的值来自主存。
  • 在Java中编写volatile时,它确保将变量的值写入主内存。

说完上述内容 - 这是从“逻辑”的角度来看。实际上,现代CPU采用复杂的缓存策略,有时可以保证上述情况不会实际写入主内存。然而,它只能实现相同的效果才能绝对实现作为性能优化步骤。但我认为这超出了讨论的范围。

答案 2 :(得分:1)

我将引用文档中的两段

first

  

字段可以声明为volatile,在这种情况下是Java Memory Model   确保所有线程都看到变量的一致值   (§17.4)。

second

  

内存模型描述了程序的可能行为。一个   实现可以自由地生成它喜欢的任何代码,只要全部   由此产生的程序执行产生的结果可以是   由记忆模型预测。

     

这为实现者提供了大量的自由来执行无数的代码转换,包括动作的重新排序   并删除不必要的同步。

现在,如果您将参考有关votatile keyword in java的大部分教程,其中大多数将提出与您建议相同的内容,即此变量的值永远不会在本地缓存线程:所有读写操作都将直接进入“主存”

但是文档并不保证。虽然它永远不会否认它。它只是说这是可能的行为

所以我会说你的老师是对的。根据文档(而不是除了docs之外的大多数教程),Volatile关键字肯定会保证变量的值将保存在主内存中。

但是,这不会让你错,这完全取决于JVM的实现。

答案 3 :(得分:0)

这里有: https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.3.1.4 来自Java 8 SE规范:

  

字段可以声明为volatile,在这种情况下,Java Memory Model可以确保所有线程都看到变量的一致值

在“Java Concurrency in Practice”中描述了非常好的IMHO。 https://jcip.net/也许你的图书馆里有它?