为什么不允许挥发性最终字段?

时间:2015-11-11 06:00:58

标签: java multithreading concurrency final volatile

我正在设计一个名为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字段表示最终的大小,以确保没有方法可以将字段指针更改为另一个对象,并将其初始化为duriong consruction。

但是由于容器将被同时访问,我需要任何线程观察其他人所做的更改。所以,我试图宣布它volatile,以避免不必要的synchronization(我不需要互斥)。

我没有编译。为什么?有什么缘故吗?以这种方式去除场地是否没有意义?我认为这是不可能的......也许它是继承不安全的?

3 个答案:

答案 0 :(得分:3)

答案很简单:

所有保证挥发性,最终已经完成。所以这将是多余的。

有关更多详细信息,请查看axtavt的答案: Java concurrency: is final field (initialized in constructor) thread-safe?

答案 1 :(得分:2)

volatile表示对字段的读写具有特定的同步效果;如果你不能写字段,volatile没有意义,所以禁止标记字段final volatile

您不需要volatile,这对您没有帮助。 AtomicInteger的突变不是对包含AtomicInteger的字段的赋值,因此它们不会受volatile的影响。相反,AtomicInteger值的读取和修改已经具有由AtomicInteger实现本身应用的适当的线程安全机制。

答案 2 :(得分:1)

volatile变量意味着它可能被非同步线程访问,因此在每次更改之后,应始终将其值写回内存。但话说回来,你不能改变一个声明为final的变量,因此volatile在你的例子中无关紧要。