为什么不允许使用 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?
我正在设计一个名为 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?