最近InfoQ eMag我遇到了句子:
将任何字段声明为“volatile”并不意味着锁定 参与其中,所以挥发物比它便宜 使用锁的同步。但重要的是要注意 在你的方法中有多个多样化的字段
可以使它们比锁定这些方法更昂贵。
困扰我的是第二部分:
但重要的是要注意 在你的方法中有多个多样化的字段
可以使它们比锁定这些方法更昂贵
根据The JSR-133 cookbook易失性负载具有与监视器输入相同的记忆效应 第二句如何成真?
答案 0 :(得分:2)
访问volatile字段有三个影响:
synchronized
关键字不同)。long
和double
类型,访问变量访问必须是原子的(在64位体系结构上,无论如何都会发生这种情况)。输入/离开synchronized
块只有效果(1)和(2)而原子访问是隐含的,如果只在这样的块中访问long
或double
字段。此外,当然,同步块意味着锁定监视器。
我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字段更快。