2015-11-11 8 views
2

Я проектирую поточно-безопасный контейнерный класс под названием 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 поле, представляющее размер окончательной, чтобы гарантировать, что ни один метод не может изменить поле poinitng к другому объекту, а также инициализировать его duriong.

Но поскольку контейнер будет доступен одновременно, мне нужно, чтобы в любой нити наблюдались изменения, сделанные другим. Итак, я попытался объявить его volatile, а также для того, чтобы избежать ненужных synchronization (мне не нужно взаимное исключение).

Я не компилировал. Зачем? Есть ли причина? Не имеет смысла декальрировать поле таким образом? Я думал, что это будет неприемлемо ... Может, это наследуется небезопасно?

ответ

3

Ответ прост:

Все гарантии Летучие делает, делается окончательными уже. Так что это было бы лишним.

Посмотрите на ответ здесь от axtavt для получения более подробной информации: Java concurrency: is final field (initialized in constructor) thread-safe?

+0

На самом деле, я думал, что visilibilty тоже относится к состоянию объекта. Это о назначении .... –

2

volatile означает, что чтение и запись в поле имеют определенные эффекты синхронизации; если вы не можете писать в поле, volatile не имеет смысла, поэтому маркировка поля final volatile запрещена.

Вам не нужен volatile, и это не поможет. Мутации для AtomicInteger не являются присвоением поля, которое содержит AtomicInteger, поэтому в любом случае они не будут затронуты volatile. Вместо этого в чтениях и изменениях значения AtomicInteger уже есть соответствующие механизмы защиты потоков, применяемые самой реализацией AtomicInteger.

+0

Ах, видимость общих переменных не включает видимость своих государств, но и изменение ссылки, верно? –

+0

@ St.Antario - Предполагая, что вы говорите о ссылочных типах .... да. То, что вы сказали, для примитивных типов не имеет смысла. –

+0

@ St.Antario, вы объединяете переменные с объектами, когда сравниваете «видимость переменных» с «видимостью их состояний». Состояние переменной - это _value_, но значение переменной 'AtomicInteger' - это просто _reference_ для атомарного целочисленного объекта. Целое число хранится в объекте, а не в переменной. –

1

Изменчивая переменная означает, что к ней могут обращаться несинхронизированные потоки, поэтому ее значение всегда должно быть записано в память после каждого изменения. Но опять же, вы не можете изменить переменную, объявленную как final, поэтому волатильность не имеет значения в вашем примере.

 Смежные вопросы

  • Нет связанных вопросов^_^