Ответ Вакаса очень ясный и полный, однако я хотел бы еще раз пояснить разницу между использованием this
против getBaseContext()
или getApplication()
против getApplicationContext()
. Оба Activity
и Application
распространяются не на Context
, а на ContextWrapper
, который является
«Проксирование реализации
blockquote>Context
, которое просто делегирует все свои вызовы другомуContext
".Этот« реальный »контекст - это то, что вы получаете с помощью
getBaseContext()
.Итак, хотя
this
(дляActivity
) иgetBaseContext()
оба контекста активности, они
- (a) не относятся к одному и тому же объекту (
this != getBaseContext()
) и- (b) вызов контекста через
this
немного менее эффективен, так как вызовы проходят через дополнительный уровень косвенности. Я сомневаюсь, что это имеет какое-то практическое значение.То же самое относится к
getApplication()
vs.getApplicationContext()
.
Collections.synchronizedMap()
гарантии, что каждая атомарная операция Вы хотите работать на карте, будут синхронизироваться.
Выполнение два (или больше) операции на карте однако, должен синхронизироваться в блоке. Так да - Вы синхронизируетесь правильно.
При использовании JDK 6 затем, Вы могли бы хотеть проверить Примечание ConcurrentHashMap
putIfAbsent метод в том классе.
Это выглядит корректным мне. Если бы я должен был изменить что-нибудь, то я прекратил бы использовать Collections.synchronizedMap () и синхронизировал бы все тот же путь, только для создания его более ясным.
кроме того, я заменил бы
if (synchronizedMap.containsKey(key)) {
synchronizedMap.get(key).add(value);
}
else {
List<String> valuesList = new ArrayList<String>();
valuesList.add(value);
synchronizedMap.put(key, valuesList);
}
с
List<String> valuesList = synchronziedMap.get(key);
if (valuesList == null)
{
valuesList = new ArrayList<String>();
synchronziedMap.put(key, valuesList);
}
valuesList.add(value);
Существует потенциал для тонкой ошибки в Вашем коде.
[ ОБНОВЛЕНИЕ: , Так как он использует map.remove () это описание не полностью действительно. Я пропустил тот факт в первый раз через.:( Благодаря автору вопроса для указания на это. Я оставляю остальных, как, но изменил ведущий оператор, чтобы сказать, что существует потенциально ошибка.]
В [1 120] doWork () Вы получаете значение Списка из Карты ориентированным на многопотоковое исполнение способом. Позже, однако, Вы получаете доступ к тому списку в небезопасном вопросе. Например, один поток может использовать список в [1 121] doWork () , в то время как другой поток вызывает synchronizedMap.get (ключ) .add (значение) в [1 123] addToMap () . Те два доступ не синхронизируются. Эмпирическое правило - то, что ориентированные на многопотоковое исполнение гарантии набора не расширяются на ключи или значения, которые они хранят.
Вы могли зафиксировать это путем вставки синхронизируемого списка в карту как [1 111]
List<String> valuesList = new ArrayList<String>();
valuesList.add(value);
synchronizedMap.put(key, Collections.synchronizedList(valuesList)); // sync'd list
, Кроме того, Вы могли синхронизироваться на карте при доступе к списку в [1 124] doWork () :
public void doWork(String key) {
List<String> values = null;
while ((values = synchronizedMap.remove(key)) != null) {
synchronized (synchronizedMap) {
//do something with values
}
}
}
последняя опция ограничит параллелизм немного, но является несколько более ясным IMO.
кроме того, быстрое примечание о ConcurrentHashMap. Это - действительно полезный класс, но является не всегда соответствующей заменой для синхронизируемого HashMaps. При заключении в кавычки из его Javadocs
Этот класс полностью совместим с Хеш-таблицей в программах, которые полагаются на его потокобезопасность , но не в его деталях синхронизации .
, Другими словами, putIfAbsent () является большим для атомарных вставок, но не гарантирует, что другие части карты не изменятся во время того вызова; это гарантирует только атомарность. В Вашем примере программы Вы полагаетесь на детали синхронизации (синхронизируемый) HashMap для вещей кроме помещенного () s.
Последняя вещь.:) Эта большая кавычка от Параллелизм Java на практике всегда помогает мне в разработке отлаживающие многопоточные программы.
Для каждой изменяемой переменной состояния, к которой может получить доступ больше чем один поток, все доступы к той переменной должны быть выполнены с той же сохраненной блокировкой.
Выезд Google Collections ' Multimap
, например, страница 28 эта презентация .
, Если Вы не можете пользоваться той библиотекой по некоторым причинам, рассмотрите использование ConcurrentHashMap
вместо SynchronizedHashMap
; это имеет остроту putIfAbsent(K,V)
метод, с которым можно атомарно добавить список элемента, если это уже не там. Кроме того, рассмотрите использование CopyOnWriteArrayList
для значений карты если Ваш ордер шаблонов использования, делающий так.