【问题标题】:Why are not volatile final fields permitted?为什么不允许 volatile final 字段?
【发布时间】:2015-11-11 06:00:57
【问题描述】:

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

接口:

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字段设为final,以确保没有任何方法可以将字段指向另一个对象,并在构建过程中对其进行初始化。

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

我没有编译。为什么?有什么理由吗?以这种方式标记一个字段没有意义吗?我认为这很明智......也许它天生就不安全?

【问题讨论】:

    标签: java multithreading concurrency final volatile


    【解决方案1】:

    答案很简单:

    volatile 所做的所有保证都已由 final 完成。所以这将是多余的。

    查看来自 axtavt 的答案以获取更多详细信息: Java concurrency: is final field (initialized in constructor) thread-safe?

    【讨论】:

    • 实际上,我认为可见性也扩展到对象的状态。这是关于任务....
    【解决方案2】:

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

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

    【讨论】:

    • 啊,共享变量的可见性不包括其状态的可见性,而是改变引用,对吧?
    • @St.Antario - 假设你在谈论引用类型......是的。对于原始类型,你说的没有意义。
    • @St.Antario,当您将“变量的可见性”与“它们的状态的可见性”进行比较时,您将变量与对象混为一谈。变量的状态是它的,但AtomicInteger 变量的值只是对原子整数对象的引用。整数存储在对象中,而不是变量中。
    • @St.Antario,另外,user2357112 告诉你的是,AtomicInteger 上的 get 和 set 操作就像 volatile int 的加载和存储一样工作。
    【解决方案3】:

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

    【讨论】:

      最近更新 更多