简体   繁体   中英

Why are not volatile final fields permitted?

I'm designing a thread-safe container class called ConcurrentParamters . here is what I tend to write:

Interfaces:

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();
}

Implementation:

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();
    }
}

I tried to make the AtomicInteger field representing the size final, to ensure that no method can change the field poinitng to another object, as well as initialize it duriong consruction.

But since the container will be accessed concurrently, I need that any thread observes changes made by other. So, I tried to declared it volatile as well in order ot avoid unnecessary synchronization (I don't need mutual-exclusion).

I didn't compile. Why? Is there any reason? Does it make no sense to decalre a field that way? I thought it would be sesnsible... Maybe it is inheritly not safe?

The answer is simple:

All guarantees volatile makes, are done by final already. So it would be redundant.

Take a look at the answer here from axtavt for more detailed information: Java concurrency: is final field (initialized in constructor) thread-safe?

volatile means that reads and writes to the field have specific synchronization effects; if you cannot write to the field, volatile makes no sense, so marking a field final volatile is forbidden.

You don't need volatile , and it wouldn't help. Mutations to an AtomicInteger are not assignments to the field that holds the AtomicInteger, so they wouldn't be affected by volatile anyway. Instead, reads and modifications of an AtomicInteger's value already have the appropriate thread-safety mechanisms applied by the AtomicInteger implementation itself.

A volatile variable means that it may be accessed by unsynchronized threads so its value should always be written back to memory after each and every change to it. But then again, you can't change a variable declared as final, thus volatile is irrelevant in your example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM