【问题标题】:How does volatile actually work?volatile实际上是如何工作的?
【发布时间】:2011-02-11 06:34:07
【问题描述】:

在 Java 中将变量标记为 volatile 可确保每个线程都看到上次写入它的值,而不是某个陈旧的值。我想知道这实际上是如何实现的。 JVM 是否会发出特殊指令来刷新 CPU 现金或其他什么?

【问题讨论】:

标签: java concurrency volatile


【解决方案1】:

具体发生的情况是特定于处理器的。通常有某种形式的内存屏障指令。刷新整个缓存显然会非常昂贵 - 硬件中有缓存一致性协议。

同样重要的是,某些优化不是跨字段访问进行的。在考虑多线程时,编译器很重要,不要只考虑硬件。

【讨论】:

  • 在正确编写的 Java 程序中发生的确切情况与处理器无关。
  • @jgubby 该问题确实询问是否发出特殊指令。
【解决方案2】:

据我了解,它总是看起来好像缓存在写入后已被刷新,并且总是看起来好像读取是在读取时直接从内存中进行的。效果是一个线程将始终看到来自另一个线程的写入结果,并且(根据 Java 内存模型)永远不会看到缓存值。但是,实际实现和 CPU 指令会因架构而异。

如果你在多个线程中增加变量,或者检查它的值并采取一些措施,它并不能保证正确性,因为显然没有实际的同步。如果只有线程写入变量而其他线程都在读取,则通常只能保证正确执行。

另请注意,64 位非易失性变量可以作为两个 32 位变量读取/写入,因此 32 位变量在写入时是原子的,但 64 位变量不是。一半可以在另一半之前写入 - 因此读取的值可能是旧值或新值。

这是我书签中非常有用的页面:

http://www.cs.umd.edu/~pugh/java/memoryModel/

【讨论】:

  • @jgubby:您的最后一段似乎不正确:您无法读取一个 64 位易失性文件,该 64 位易失性文件在一次写入中具有 32 位,而在另一次写入中具有 32 位。
  • @WizardOfOdds:同意。意思是说那里的非易失性变量。
  • @jbuggy: 啊啊,我就是这么想的,但我不敢编辑你的帖子,因为我不确定你的意思:) 很高兴能提供帮助,否则会有点混乱: )))
  • 看到另一个线程的写入归结为 happens-before 关系。如果不违反 happens-before 规则,则对volatiles 的更新不一定会立即更新。例如,如果两者之间没有发生其他 happens-before 行为,编译器可以将两次写入合并到 volatile。
猜你喜欢
  • 2021-01-21
  • 2011-09-27
  • 2021-12-16
  • 2013-03-14
  • 2021-03-23
  • 2017-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多