我和老师讨论过java中的volatile
关键字。
当变量被声明为volatile
:
此变量的值永远不会缓存在线程本地:all 读取和写入将直接进入"主存["。
我的老师的意见是:
volatile
关键字不承诺变量的值 保存在主存中。
有人可以解决我们的冲突吗?谢谢!
答案 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。
针对您的具体问题。
volatile
时,它确保变量的值来自主存。volatile
时,它确保将变量的值写入主内存。说完上述内容 - 这是从“逻辑”的角度来看。实际上,现代CPU采用复杂的缓存策略,有时可以保证上述情况不会实际写入主内存。然而,它只能实现相同的效果才能绝对实现作为性能优化步骤。但我认为这超出了讨论的范围。
答案 2 :(得分:1)
我将引用文档中的两段
字段可以声明为volatile,在这种情况下是Java Memory Model 确保所有线程都看到变量的一致值 (§17.4)。
内存模型描述了程序的可能行为。一个 实现可以自由地生成它喜欢的任何代码,只要全部 由此产生的程序执行产生的结果可以是 由记忆模型预测。
这为实现者提供了大量的自由来执行无数的代码转换,包括动作的重新排序 并删除不必要的同步。
现在,如果您将参考有关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/也许你的图书馆里有它?