2012-02-17 1 views
25

Если в классе у меня есть экземпляр ConcurrentHashMap, который будет изменен и читать несколько потоков я мог бы определить так:Почему переменная-член объекта не является окончательной и изменчивой в Java?

public class My Class { 

    private volatile ConcurrentHashMap<String,String> myMap = new ConcurrentHashMap<String,String>(); 
... 
} 

добавление final к результатам MyMap поля к ошибке говоря, что я могу использовать только окончательный или неустойчивый. Почему это может быть не так?

+0

несколько связанных http://stackoverflow.com/questions/2964206/java-concurrency-volatile-vs-final-in-cascaded-variables – Jayan

ответ

23

volatile имеет значение только для модификаций самой переменной, а не для объекта, к которому она относится. Нет смысла иметь поле final volatile, потому что окончательные поля не могут быть изменены. Просто объявите поле final, и все должно быть хорошо.

+0

как раз пояснить ваш комментарий, что «окончательные поля не могут быть изменены»; конечные поля, по сути, изменяемы, но конечное ключевое слово разрешает только однократное присвоение. – johntrepreneur

+3

@johnterpreneur: это неверно; конечные поля могут быть назначены * только при построении объекта *, что в значительной степени является определением «неизменяемым». –

+0

, если использование ключевого слова 'final' сделало объекты неизменными, как вы заявили, тогда объявление конечной переменной члена' StringBuilder' не позволит вам изменить его. Однако вы можете изменить его и вызвать '.append' для изменения объекта. – johntrepreneur

2

volatile используется для переменных, их значение может меняться, в некоторых случаях, в противном случае нет необходимости в volatile и final означает, что переменная не может измениться, так что нет никакой необходимости в volatile.

Ваших параллельности проблемы очень важны, но делают HashMapлетучего не решит проблему, для обработки проблем параллелизма, вы уже используете ConcurrentHashMap.

+0

Вы не можете создать HashMap (или любой другой объект) 'volatile'. Ключевое слово «volatile» влияет на переменную, а не на объекты, к которым может относиться переменная. –

7

Поскольку volatile и final две крайние концы в Java

volatile означает, что переменная связана с изменениями

final означает, что значение переменной не изменится вообще

1

Потому что это не иметь смысл. Volatile влияет на ссылочное значение объекта, а не на поля объекта/etc.

В вашей ситуации (у вас есть параллельная карта) вы должны сделать поле final.

1

модификатор гарантирует, что все считывания и записи перейдут в основную память, то есть как доступ к переменной почти в . Это не имеет значения для конечной переменной, которая не может быть изменена.

21

Это из-за модели памяти Java (JMM).

По существу, когда вы объявляете поле объекта как final, вам необходимо инициализировать его в конструкторе объекта, а затем поле final не изменит его значение. И JMM обещает, что после завершения ctor любой поток увидит то же (правильное) значение поля final. Таким образом, вам не нужно использовать явную синхронизацию, такую ​​как synchronize или Lock, чтобы разрешить всем потокам видеть правильное значение поля final.

Когда вы объявляете поле объекта как volatile, значение поля может меняться, но при каждом чтении значения из любого потока будет отображаться последнее значение, записанное на него.

Таким образом, final и volatile достигают той же цели - видимость значения поля объекта, но в первую очередь используется для переменной, которая может быть назначена только один раз и второй для переменной, которую можно менять многократно.

Ссылки:

+0

Объяснение для меня довольно хорошее, но я бы не сказал, что final используется для «постоянных» значений. Это утверждение немного вводит в заблуждение, хотя я понимаю, что вы хотели сказать. –

+1

«Конечная и неустойчивая» достигают той же цели ... «Я думаю, что это поставить телегу перед лошадью. _purpose_ 'final' заключается в том, чтобы объявить, что переменная или поле не должны быть назначены. _purpose_ 'volatile' заключается в том, чтобы сообщить компилятору, что значение не может быть выведено путем изучения кода. Тот факт, что модель памяти Java имеет специальные правила относительно видимости каждого из этих двух видов переменных, является вторичной по отношению к их неперекрывающимся целям. –

4

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

final поле не может быть изменено (Что ссылаться на поля могут быть изменены)

Это не имеет никакого смысла иметь оба.

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