2

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?

St.Antario
  • 26,175
  • 41
  • 130
  • 318

3 Answers3

3

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?

Community
  • 1
  • 1
Denis Lukenich
  • 3,084
  • 1
  • 20
  • 38
2

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.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • Ah, the visibility of shared variables doesn't include the visibility of their states, but changing the references, right? – St.Antario Nov 11 '15 at 06:21
  • @St.Antario - Assuming that you are talking about reference types .... yes. For primitive types, what you said makes no sense. – Stephen C Nov 11 '15 at 07:55
  • @St.Antario, you are conflating variables with objects when you compare "visibility of variables" with "visibility of their states." The state of a variable is its _value_, but the value of an `AtomicInteger` variable is just the _reference_ to the atomic integer object. The integer is stored in the object, not in the variable. – Solomon Slow Nov 11 '15 at 13:41
  • @St.Antario, also, what user2357112 is telling you is that the get and set operations on an `AtomicInteger` work like loads and stores of a `volatile int`. – Solomon Slow Nov 11 '15 at 13:44
1

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.