Параллелизм Java: Энергозависимый по сравнению с финалом в “каскадных” переменных?

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);

В случае, если это НЕ является "каскадной" картой, окончательный и энергозависимый имеют в конце тот же эффект создания Shure, что все потоки всегда видят корректное содержание Карты... Но что происходит, если Карта iteself содержит карту, как в примере... Как я делаю Shure, что внутренняя Карта является правильно "Огражденной барьером памятью"?

Корпуса! Tom

6
задан jasonmp85 3 June 2010 в 08:20
поделиться

3 ответа

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

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

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

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

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

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

Резюме

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

9
ответ дан 8 December 2019 в 17:18
поделиться

Стоит посмотреть на Google-Collections и, в частности, на 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, так как оно кажется неправильным.

4
ответ дан 8 December 2019 в 17:18
поделиться

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

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

1
ответ дан 8 December 2019 в 17:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: