我正在设计一个名为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
(我不需要互斥)。
我没有编译。为什么?有什么缘故吗?以这种方式去除场地是否没有意义?我认为这是不可能的......也许它是继承不安全的?
答案 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在你的例子中无关紧要。