如果在一个类中我有一个ConcurrentHashMap实例,它将被多个线程修改和读取,我可能会这样定义:
public class My Class {
private volatile ConcurrentHashMap<String,String> myMap = new ConcurrentHashMap<String,String>();
...
}
将final
添加到myMap字段会导致错误,说我只能使用final或volatile。为什么不能两者兼而有之?
答案 0 :(得分:28)
volatile
仅与变量本身的修改有关,而与其引用的对象无关。拥有final volatile
字段是没有意义的,因为无法修改最终字段。只需声明字段final
,就可以了。
答案 1 :(得分:25)
这是因为Java内存模型(JMM)。
基本上,当您将对象字段声明为final
时,您需要在对象的构造函数中初始化它,然后final
字段不会更改它的值。 JMM承诺在ctor完成后,任何线程都会看到final
字段的相同(正确)值。因此,您不需要使用显式同步(例如synchronize
或Lock
)来允许所有线程查看final
字段的正确值。
当您将对象的字段声明为volatile
时,字段的值可以更改,但仍然可以从任何线程读取每个值的最新值。
因此,final
和volatile
实现了相同的目的 - 对象的字段值的可见性,但首先是专门用于变量的,只能分配给一次,而第二次用于变量可以多次改变。
参考文献:
答案 2 :(得分:7)
因为volatile
和final
是Java中的两个极端
volatile
表示变量绑定到更改
final
表示变量的值永远不会改变
答案 3 :(得分:4)
volatile
字段可以保证更改时发生的情况。 (没有可能引用的对象)
无法更改final
字段(可以更改字段引用的内容)
两者都没有意义。
答案 4 :(得分:2)
volatile
用于其值可能更改的变量,在某些情况下,否则不需要volatile
,而final
表示变量可能不会更改,因此有不需要volatile
。
您的并发问题很重要,但使HashMap
volatile 无法解决问题,因为处理并发问题,您已使用ConcurrentHashMap
。
答案 5 :(得分:1)
因为它没有任何意义。易失性影响对象参考值,而不是对象的字段/等。
在您的情况下(您有并发地图),您应该执行字段final
。
答案 6 :(得分:1)
volatile
修饰符保证所有读写都会进入主内存,即变量访问几乎进入synchronized
块。这与无法更改的最终变量无关。