Параллелизм Java: Volatile vs final в" Каскадных " переменных?
is
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 в конечном итоге имеют тот же эффект, что и shure, что все потоки всегда видят правильное содержимое карты... Но что произойдет, если карта iteself содержит карту, как в Примере... Как мне сделать так, чтобы внутренняя карта правильно "ограждена памятью"?
танки! Тома
3 ответов
volatile
влияет только на способность других потоков считывать значение переменных, к которым он прикреплен. Это никоим образом не влияет на способность другого потока, чтобы просмотреть ключи и Значения карты. Например, я мог бы иметь volatile int[]
. Если я изменю ссылку, то есть если я изменю фактический массив, на который он указывает, другие потоки, считывающие массив, гарантированно увидят это изменение. Однако, если я изменю третий элемент массива, такие гарантии не будут сделаны.
если status
и final
, конструкция содержащего класса создает happens-before
отношение с любыми последующими чтениями, поэтому они могут видеть значение статуса. Аналогично любой читает ваш volatile
переменная гарантированно увидит последнее назначение ссылки на нее. Это не похоже на то, что вы очень часто меняете фактическую карту, больше похоже на то, что вы просто меняете ключи, и общий объект карты остается как есть.
на этот вопрос, мы должны обратиться к документации по ConcurrentHashMap
:
операции поиска (включая get) как правило, не блокируют, поэтому могут перекрываться с операциями обновления (включая put и удалить). Извлечения отражают результаты недавно завершенных обновление операций, проводимых по их начало.
это немного странно сформулировано, но суть в том, что любой get
операция, начало которой после некоторые put
возвращение деятельности гарантировано для того чтобы увидеть результаты что положено. Так что вам даже не нужно volatile
на внешней карте; quoth JLS:
поток, который может видеть только ссылку на объект, после чего объект полностью инициализирован гарантированно видеть правильно инициализированные значения для этого объекта последние поля.
резюме
A final
на внешней карте достаточно.
стоит Google-Коллекции и, в частности, картографа это позволяет разумно настраивать и создавать карты. Возможность настройки слабых значений, улучшения сбора мусора и времени истечения срока действия, чтобы вы могли использовать карты для эффективного кэширования, является блестящей. Поскольку карты, которые делает 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, как это не кажется правильным.
Я думаю, что лучший ответ здесь-это volatile
не является способом обеспечения потокобезопасности.
используя ConcurrentHashMap
почти все, что вам нужно. Да, сделайте ссылку на верхний уровень Map
final
Если вы можете, но volatile
Не надо в любом случае. Второй уровень Map
ссылка внутри-это бизнес ConcurrentHashMap
чтобы получить право, и предполагается, что это так.