Java Concurrency: Volatile против final в «каскадных» переменных? - PullRequest
6 голосов
/ 03 июня 2010

равно

final Map<Integer,Map<String,Integer>> status = new ConcurrentHashMap<Integer, Map<String,Integer>>();
Map<Integer,Map<String,Integer>> statusInner = new ConcurrentHashMap<Integer, Map<String,Integer>>();
status.put(key,statusInner);

так же, как

volatile Map<Integer,Map<String,Integer>> status = new ConcurrentHashMap<Integer,   Map<String,Integer>>();
Map<Integer,Map<String,Integer>> statusInner = new ConcurrentHashMap<Integer, Map<String,Integer>>();
status.put(key,statusInner);

в случае, если внутренняя Карта доступна из разных потоков?

или даже что-то вроде этого требуется:

volatile Map<Integer,Map<String,Integer>> status = new ConcurrentHashMap<Integer, Map<String,Integer>>();
volatile Map<Integer,Map<String,Integer>> statusInner = new ConcurrentHashMap<Integer, Map<String,Integer>>();
status.put(key,statusInner);

В случае, если это НЕ «каскадная» карта, final и volatile имеют в итоге один и тот же эффект, гарантируя, что все потоки всегда будут видеть правильное содержимое карты ... Но что произойдет, если сама карта содержит карта, как в примере ... Как мне убедиться, что внутренняя карта правильно "Память заперта"?

Танки! Том

Ответы [ 3 ]

9 голосов
/ 03 июня 2010

volatile влияет только на способность других потоков читать значение переменных, к которым он прикреплен. Это никоим образом не влияет на способность другого потока видеть ключи и значения карты. Например, у меня может быть volatile int[]. Если я поменяю ссылку - т.е. если я изменю фактический массив, на который он указывает - другие потоки, читающие массив, гарантированно увидят это изменение. Однако, если я изменю третий элемент массива, такие гарантии не будут предоставлены.

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

По этому вопросу нам нужно обратиться к документации для ConcurrentHashMap:

Операции поиска (включая получение) как правило, не блокируют, поэтому могут перекрываться с операциями обновления (включая пут и удалить). Извлечения отражают результаты самых последних завершенных обновить операции, держась за их начало.

Это несколько странно сформулировано, но суть в том, что любая операция get, начало которой равно после возврата некоторой операции put, гарантированно увидит результаты этого пута. Так что вам даже не нужно volatile на внешней карте; "JLS":

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

Краткое описание

A final на внешней карте достаточно.

4 голосов
/ 03 июня 2010

Стоит взглянуть на Google-Коллекции и, в частности, MapMaker , который позволяет интеллектуально настраивать и создавать Карты. Замечательно иметь возможность устанавливать слабые значения, обеспечивать лучшую сборку мусора и время истечения, поэтому вы можете использовать Карты для эффективного кэширования. Поскольку Карты, которые MapMaker создает (: p), имеют те же свойства, что и ConcurrentHashMap, вы можете быть довольны его безопасностью потоков.

final mapMaker = new MapMaker().weakValues(); //for convenience, assign
final Map<Integer,Map<String,Integer>> status = mapMaker.makeMap();
status.put(key, mapMaker.<String, Integer>makeMap());

Обратите внимание, что вы можете посмотреть на ваше определение statusInner, так как оно кажется неправильным.

1 голос
/ 03 июня 2010

Я думаю, что лучший ответ здесь заключается в том, что volatile не является способом обеспечения безопасности потоков.

Использование ConcurrentHashMap - это почти все, что вам нужно.Да, сделайте ссылку на верхний уровень Map final, если можете, но volatile не требуется в любом случае.Ссылка Map второго уровня внутри - дело ConcurrentHashMap, чтобы получить право, и каждый предполагает, что это делает.

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