java 中的 volatile 关键字

Volatile keyword in java under the hood

我和老师就java中的volatile关键字发生了一点争执。 当变量声明为 volatile:

时这样说对吗

The value of this variable will never be cached thread-locally: all reads and writes will go straight to the "main memory".

我老师的意见是:

volatile keyword does not promise the value of the variable will be saved in the main memory.

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

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

A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable

恕我直言,"Java Concurrency in Practice" 中对它的描述非常好。 https://jcip.net/ 也许你的图书馆里有它?

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

JLS paragraph 8.3.1.4 解释了 volatile 的含义:

A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable (§17.4).

Paragraph 17.4 解释了 Java 内存模型。内存模型为您提供了关于程序中每条语句之后数据会发生什么的某些保证。

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

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

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

除此之外,volatile还有原子操作保证。它确保以该关键字为前缀的变量将被完整读取或写入,就好像它是一条指令一样。 (作为对比,您不必担心由 2 个线程写入的 64 位长整数最终会以一个线程的第一个 32 位和另一个线程的第二个 32 位结束。)因此在某些特定情况下,例如如果您在 32 位机器上对 64 位长整数使用 volatile,则 JVM 可能需要做的不仅仅是 "volatile" 指令。更多文档位于 https://blogs.oracle.com/dave/entry/java_memory_model_concerns_on .

针对您的具体问题。

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

综上所述 - 这是从 "logical" 的角度来看的。实际上,现代 CPUs 采用了复杂的缓存策略,它有时可以在不实际写入主内存的情况下保证上述内容是正确的。然而,它只是在实现相同效果时才这样做,作为性能优化步骤绝对可以实现。不过我觉得这不在讨论范围内。

我只引用文档中的两段

first

A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable (§17.4).

second

The memory model describes possible behaviors of a program. An implementation is free to produce any code it likes, as long as all resulting executions of a program produce a result that can be predicted by the memory model.

This provides a great deal of freedom for the implementor to perform a myriad of code transformations, including the reordering of actions and removal of unnecessary synchronization.


现在,如果您将参考大多数关于 votatile keyword in java 的教程,它们中的大多数会建议与您建议的相同的内容,即 永远不会缓存此变量的值线程本地:所有读写都将直接进入 "main memory"

但是文档对此没有任何保证。虽然它也从不否认。它只是说 这是可能的行为

所以我会说你的老师是正确的。根据文档(而不是除了文档以外的大多数教程),Volatile 关键字确实 而不是 承诺变量的值将保存在主内存中。

然而,这不会让你错,这完全取决于 JVM 实现。