42

我知道写入volatile变量会从所有 cpu 的内存中刷新它,但是我想知道对 volatile 变量的读取是否与正常读取一样快?

变量可以volatile放置在 cpu 缓存中还是总是从主内存中获取?

4

5 回答 5

20

你真的应该看看这篇文章:http ://brooker.co.za/blog/2012/09/10/volatile.html 。博客文章认为,易失性读取(对于 x86 也是如此)比 x86 上的非易失性读取要慢得多。

  • 测试 1 是对非易失性变量的并行读写。没有可见性机制,读取的结果可能过时。
  • 测试 2 是对 volatile 变量的并行读写。这并没有具体解决 OP 的问题。然而值得注意的是,有争议的 volatile 可能非常缓慢。
  • 测试 3 是在紧密循环中对 volatile 的读取。证明了易失性的语义表明该值可以随着每次循环迭代而改变。因此,JVM 无法优化读取并将其提升出循环。在测试 1 中,该值很可能被读取和存储一次,因此没有发生实际的“读取”。

马克布克的测试

感谢 Marc Booker 运行这些测试。

于 2012-09-10T18:21:01.947 回答
13

答案在某种程度上取决于架构。在 x86 上,没有与易失性读取相关的额外开销,尽管对其他优化有影响。

Doug Lea 的 JMM 食谱,请参阅底部附近的架构表。

澄清一下:读取本身没有任何额外的开销。内存屏障用于确保正确排序。JSR-133 将四个屏障分类为“LoadLoad、LoadStore、StoreLoad 和 StoreStore”。根据架构的不同,其中一些障碍对应于“无操作”,这意味着不采取任何行动,而其他障碍则需要围栏。负载本身没有隐含成本,但如果设置了栅栏,可能会产生成本。在 x86 的情况下,只有 StoreLoad 屏障会导致栅栏。

正如博客文章中所指出的,变量是 volatile 的事实意味着无法再对变量的性质进行假设,并且某些编译器优化不会应用于 volatile。

Volatile 不是应该随便使用的东西,但也不应该害怕。在很多情况下,一个 volatile 就足以代替更繁重的锁定。

于 2009-07-07T04:39:09.403 回答
2

它依赖于架构。什么volatile是告诉编译器不要优化该变量。它强制大多数操作将变量的状态视为未知数。因为它是易失的,它可以被另一个线程或其他一些硬件操作改变。因此,读取将需要重新读取变量,并且操作将属于读取-修改-写入类型。

这种变量用于设备驱动程序,也用于与内存中的互斥体/信号量同步。

于 2009-07-07T05:37:46.150 回答
-1

易失性读取不能那么快,尤其是在多核 CPU(但也只有单核)上。执行核心必须从实际内存地址中获取以确保它获得当前值——该变量确实不能被缓存。

与此处的另一个答案相反,易失性变量不仅仅用于设备驱动程序!它们有时对于编写高性能多线程代码至关重要!

于 2009-07-07T04:47:15.707 回答
-2

volatile 意味着编译器无法通过将变量值放在 CPU 寄存器中来优化变量。它必须从主存访问。但是,它可以放在 CPU 缓存中。缓存将保证系统中任何其他 CPU/内核之间的一致性。如果内存映射到IO,那么事情就复杂了一些。如果它是这样设计的,硬件将阻止该地址空间被缓存,并且对该内存的所有访问都将转到硬件。如果没有这样的设计,硬件设计人员可能需要额外的 CPU 指令来确保读/写通过缓存等。

通常,“volatile”关键字仅用于操作系统中的设备驱动程序。

于 2009-07-07T04:33:15.827 回答