Java中的多个volatile字段性能与同步块

时间:2016-03-29 13:31:10

标签: java concurrency java-memory-model

最近InfoQ eMag我遇到了句子:

  

将任何字段声明为“volatile”并不意味着锁定   参与其中,所以挥发物比它便宜   使用锁的同步。但重要的是要注意   在你的方法中有多个多样化的字段
  可以使它们比锁定这些方法更昂贵。

困扰我的是第二部分:

  

但重要的是要注意   在你的方法中有多个多样化的字段
  可以使它们比锁定这些方法更昂贵

根据The JSR-133 cookbook易失性负载具有与监视器输入相同的记忆效应 第二句如何成真?

2 个答案:

答案 0 :(得分:2)

访问volatile字段有三个影响:

  1. VM要求程序遵守周围变量的同步顺序(与synchronized关键字不同)。
  2. 访问volatile字段的线程需要将其缓存与访问此volatile字段的其他线程同步。
  3. 对于longdouble类型,访问变量访问必须是原子的(在64位体系结构上,无论如何都会发生这种情况)。
  4. 输入/离开synchronized块只有效果(1)和(2)而原子访问是隐含的,如果只在这样的块中访问longdouble字段。此外,当然,同步块意味着锁定监视器。

    have given talks on the details of these effects在很多场合如果您想了解更多信息。在Stack Overflow上完全覆盖它太复杂了。

    实际上,大多数虚拟机都过度满足这些要求。例如,HotSpot VM接近JMM-cookbook的建议,并在访问volatile变量后发出内存障碍。在添加synchronized块之前和之后添加类似的内存屏障。

    如果访问 N 易失性字段的开销超过两个此类内存屏障的开销加上获取互斥锁,则上述statememt可以成为现实>其中一个从互斥锁中访问 N 易失性字段。我怀疑在单个同步块变得更有效之前,可以对一个人需要访问多少变量做出有意义的陈述。虚拟机非常智能,可以进行优化,例如可以进行大容量内存刷新,也可以在另一侧消除互斥锁的充满效果。我总是试图表达更加语义正确的东西;代码违反规范,而不是实现。如果你做后者,一定要正确地对你的结果进行基准测试,甚至在此之前,确保你真的需要挤出一点点的性能。

答案 1 :(得分:-1)

据我所知,一个易失性字段的行为方式与锁定时的行为方式相同。在大多数 JVM实现中,它不会使用锁(尽管可能)。

据我所知,volatile关键字不保证原子操作。所有volatile操作(包括double和long)都保证是原子操作。您可能在此处遇到了丢失更新问题(因为它实际上并未同步/阻止)。如果您想要原子操作,请使用Atomic类或自己同步。

我不知道确切的定义,它在Java 5中也有所改变。我在这里说的只是一个方向,但不要使用我所说的构建应用程序:)

修改

以下是来自Oracle的Atomic Access tutorial的重要句子。

  

[...]对volatile变量的任何写入都会建立一个先发生过的事件   与后续读取同一变量的关系。

因此,如果您执行单个同步块,则可能比创建此关系的许多volatile字段更快。