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