Почему переменная-член Object не может быть как окончательной, так и изменчивой в Java? - PullRequest
32 голосов
/ 17 февраля 2012

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

public class My Class {

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

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

Ответы [ 7 ]

28 голосов
/ 17 февраля 2012

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

25 голосов
/ 17 февраля 2012

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

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

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

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

Ссылки:

8 голосов
/ 17 февраля 2012

Поскольку volatile и final - это два крайних конца в Java

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

final означает, что значение переменной никогда не будетизменить что бы то ни было

4 голосов
/ 17 февраля 2012
Поле

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

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

Нет смысла иметь оба.

2 голосов
/ 17 февраля 2012

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

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

1 голос
/ 17 февраля 2012
Модификатор

volatile гарантирует, что все операции чтения и записи будут проходить в основную память, т. Е. Доступ к переменной почти в блок synchronized. Это не имеет значения для конечной переменной, которую нельзя изменить.

1 голос
/ 17 февраля 2012

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...