繁体   English   中英

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

[英]Volatile keyword in java under the hood

我和老师讨论过java中的volatile关键字。 说变量被声明为volatile时是否正确:

该变量的值永远不会被线程本地缓存:所有读取和写入将直接进入“主存储器”。

我老师的意见是:

volatile关键字保证变量的值将保存在主内存中。

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

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

JLS第8.3.1.4段解释了volatile含义:

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

第17.4节解释了Java内存模型。 内存模型为您提供有关程序中每个语句之后数据发生情况的某些保证。

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

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

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采用复杂的缓存策略,有时可以保证上述情况不会实际写入主内存。 然而,它只能实现相同的效果才能绝对实现作为性能优化步骤。 但我认为这超出了讨论的范围。

我将引用文档中的两段

第一

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

第二

内存模型描述了程序的可能行为。 只要程序的所有结果执行产生可由内存模型预测的结果,实现就可以自由地生成它喜欢的任何代码。

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


现在,如果您将参考大多数关于votatile keyword in java的教程, votatile keyword in java大多数教程都会提出与您建议的相同的东西,即, 此变量的值永远不会被线程本地缓存:所有读取和写入都将直接进行到“主要记忆”

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

所以我会说你的老师是对的。 根据文档(而不是比其他文档的最教程)volatile关键字绝对答应,该变量的值将被保存在主存储器。

但是,这不会让你错,这一切都取决于JVM的实现。

在这里: 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/也许你的图书馆里有它?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM