Java синхронизировал блок по сравнению с Collections.synchronizedMap

Ответ Вакаса очень ясный и полный, однако я хотел бы еще раз пояснить разницу между использованием this против getBaseContext() или getApplication() против getApplicationContext(). Оба Activity и Application распространяются не на Context, а на ContextWrapper, который является

«Проксирование реализации Context, которое просто делегирует все свои вызовы другому Context ".

Этот« реальный »контекст - это то, что вы получаете с помощью getBaseContext().

Итак, хотя this (для Activity) и getBaseContext() оба контекста активности, они

  • (a) не относятся к одному и тому же объекту ( this != getBaseContext()) и
  • (b) вызов контекста через this немного менее эффективен, так как вызовы проходят через дополнительный уровень косвенности. Я сомневаюсь, что это имеет какое-то практическое значение.

То же самое относится к getApplication() vs. getApplicationContext().

81
задан Ryan Ahearn 19 February 2009 в 20:44
поделиться

5 ответов

Collections.synchronizedMap() гарантии, что каждая атомарная операция Вы хотите работать на карте, будут синхронизироваться.

Выполнение два (или больше) операции на карте однако, должен синхронизироваться в блоке. Так да - Вы синхронизируетесь правильно.

87
ответ дан Yuval Adam 5 November 2019 в 17:23
поделиться

При использовании JDK 6 затем, Вы могли бы хотеть проверить Примечание ConcurrentHashMap

putIfAbsent метод в том классе.

14
ответ дан TofuBeer 5 November 2019 в 17:23
поделиться

Это выглядит корректным мне. Если бы я должен был изменить что-нибудь, то я прекратил бы использовать 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);
4
ответ дан Paul Tomblin 5 November 2019 в 17:23
поделиться

Существует потенциал для тонкой ошибки в Вашем коде.

[ ОБНОВЛЕНИЕ: , Так как он использует 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 на практике всегда помогает мне в разработке отлаживающие многопоточные программы.

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

13
ответ дан JLR 5 November 2019 в 17:23
поделиться

Выезд Google Collections ' Multimap, например, страница 28 эта презентация .

, Если Вы не можете пользоваться той библиотекой по некоторым причинам, рассмотрите использование ConcurrentHashMap вместо SynchronizedHashMap; это имеет остроту putIfAbsent(K,V) метод, с которым можно атомарно добавить список элемента, если это уже не там. Кроме того, рассмотрите использование CopyOnWriteArrayList для значений карты если Ваш ордер шаблонов использования, делающий так.

2
ответ дан Barend 5 November 2019 в 17:23
поделиться
Другие вопросы по тегам:

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