易失性变量“读取”的速度是否与正常读取一样快?

2022-09-01 01:38:12

我知道写入变量会将其从所有cpu的内存中刷新出来,但是我想知道对易失性变量的读取速度是否与正常读取一样快?volatile

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


答案 1

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

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

Marc Booker's tests

感谢 Marc Booker 运行这些测试。


答案 2

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

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

澄清一下:读取本身没有任何额外的开销。内存屏障用于确保正确的排序。JSR-133 对四个障碍“LoadLoad、LoadStore、StoreLoad 和 StoreStore”进行了分类。根据架构的不同,其中一些障碍对应于“no-op”,这意味着不采取任何行动,其他障碍则需要围栏。没有与负载本身相关的隐性成本,但如果围栏到位,可能会产生隐性成本。在 x86 的情况下,只有 StoreLoad 障碍物才会形成围栏。

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

挥发性不是应该轻描淡写地使用的东西,但也不应该害怕。在很多情况下,挥发性就足够了,可以代替更重的锁定。


推荐