为什么 Object 成员变量在 Java 中不能既是最终的又是易失性的



如果在类中我有一个ConcurrentHashMap实例,该实例将被多个线程修改和读取,我可能会这样定义:

public class My Class {
    private volatile ConcurrentHashMap<String,String> myMap = new ConcurrentHashMap<String,String>();
...
}

final添加到 myMap 字段会导致错误,指出我只能使用 final 或易失性。为什么不能两者兼而有之?

volatile只与变量本身的修改相关,而不与它所引用的对象相关。拥有final volatile字段是没有意义的,因为最终字段无法修改。只需声明字段final,它应该没问题。

这是因为

Java内存模型(JMM(。

本质上,当您将对象字段声明为 final 时,您需要在对象的构造函数中初始化它final然后字段不会更改其值。JMM承诺,在ctor完成后,任何线程都将看到final字段的相同(正确(值。因此,无需使用显式同步(如 synchronizeLock(即可允许所有线程查看final字段的正确值。

当您将对象的字段声明为 volatile 时,字段的值可以更改,但每次从任何线程读取值都会看到写入的最新值。

因此,finalvolatile达到相同的目的 - 对象的字段值的可见性,但第一个是专门用于一个变量只能分配给一次,第二个用于可以多次更改的变量。

引用:

  • http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4

  • http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4

因为volatilefinal是Java中的两个极端

volatile表示变量绑定到更改

final意味着变量的值永远不会改变

volatile用于

变量,在某些情况下,它们的值可能会改变,否则不需要volatilefinal意味着变量可能不会改变,所以不需要volatile

您的并发问题很重要,但使HashMap不稳定并不能解决问题,为了处理并发问题,您已经使用了 ConcurrentHashMap

volatile字段为您提供了更改时会发生什么的保证。(没有可能引用的对象(

无法更改final字段(可以更改字段引用的内容(

两者兼而有之是没有意义的。

volatile修饰符保证所有读取和写入都直接进入主内存,即就像变量访问几乎进入synchronized块一样。这与无法更改的最终变量无关。

因为它没有任何意义。易失性会影响对象的引用值,而不是对象的字段/等。

在您的情况下(您有并发映射(,您应该执行字段final

在多线程环境中,不同的线程将从主内存中读取变量并将其添加到 CPU 缓存中。这可能会导致两个不同的线程对同一变量进行更改,同时忽略彼此的结果。在此处输入图像描述

我们使用单词volatile 来表示变量将保存在主内存中并从主内存中读取。因此,每当线程想要读/写变量时,它都会从主内存中完成,本质上使变量在多线程环境中安全。

当我们使用 final 关键字时,我们表示变量不会改变。如您所见,变量是否不可更改,那么多个线程是否使用它并不重要。没有线程可以更改变量,因此即使变量在不同时间保存到 CPU 缓存中,并且线程也会在不同的时间使用此变量,因为它仍然可以,因为变量只能被读取。

最新更新