为什么不允许使用 volatile final 字段?

Why are not volatile final fields permitted?

我正在设计一个名为 ConcurrentParamters 的线程安全容器 class。这是我倾向于写的内容:

接口:

public interface Parameters {
    public <M> M getValue(ParameterMetaData<M> pmd);
    public <M> void put(ParameterMetaData<M> p, M value);
    public int size();
}
public interface ParameterMetaData<ValueType> {
    public String getName();
}

实施:

public final class ConcurrentParameters implements Parameters{

    private final Map<ParameterMetaData<?>, Object> parameters;
    private final volatile AtomicInteger size; //1, Not compile
    {
        size = new AtomicInteger();
        parameters = new ConcurrentHashMap<>();
    }

    public static Parameters emptyParameters(){
        return new ConcurrentParameters();
    }

    @Override
    public <M> M getValue(ParameterMetaData<M> pmd) {
        M value = (M) parameters.get(pmd);
        return value;
    }

    @Override
    public <M> void put(ParameterMetaData<M> p, M value){
        parameters.put(p, value);
        size.incrementAndGet();
    }

    @Override
    public int size() {
        return size.intValue();
    }
}

我尝试将表示大小的 AtomicInteger 字段设为最终字段,以确保没有任何方法可以将字段指向另一个对象,并在构建过程中对其进行初始化。

但由于容器将被并发访问,我需要任何线程观察其他线程所做的更改。所以,我也试图声明它 volatile 以避免不必要的 synchronization (我不需要互斥)。

我没有编译。为什么?有什么理由吗?以这种方式给一个字段贴花没有意义吗?我以为它会是 sesnsible...也许它继承不安全?

volatile表示对该字段的读写有特定的同步效果;如果您不能写入字段,volatile 没有意义,因此禁止标记字段 final volatile

您不需要 volatile,这也无济于事。对 AtomicInteger 的更改不是对保存 AtomicInteger 的字段的赋值,因此它们无论如何都不会受到 volatile 的影响。相反,读取和修改 AtomicInteger 的值已经具有由 AtomicInteger 实现本身应用的适当的线程安全机制。

volatile 变量意味着它可能会被非同步线程访问,因此每次更改后都应将其值写回内存。但是话又说回来,您不能更改声明为 final 的变量,因此 volatile 在您的示例中无关紧要。

答案很简单:

所有保证 volatile 已经由 final 完成。所以它会是多余的。

查看此处来自 axtavt 的答案,了解更多详细信息: Java concurrency: is final field (initialized in constructor) thread-safe?