Шаблон для Java ConcurrentHashMap Наборов - PullRequest
4 голосов
/ 22 марта 2012

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

Шаблон, который я использовал:

final ConcurrentMap<KEYTYPE, Set<VALUETYPE>> hashMap = new ConcurrentHashMap<KEYTYPE, Set<VALUETYPE>>();
// ...
Set<VALUETYPE> newSet = new HashSet<VALUETYPE>();
final Set<VALUETYPE> set = hashMap.putIfAbsent(key, newSet)
if (set != null) {
  newSet = set;
}
synchronized (newSet) {
  if (!newSet.contains(value)) {
    newSet.add(value);
  }
}

Есть ли лучший шаблон для выполнения этой операции?Это даже потокобезопасно?Есть ли лучший класс для внутреннего Set, чем java.util.HashSet?

Ответы [ 2 ]

5 голосов
/ 22 марта 2012

Я настоятельно рекомендую использовать для этого библиотеки Google Guava , в частности реализацию Multimap . HashMultimap будет вашим лучшим выбором, хотя, если вам нужны параллельные обновления, вам нужно будет обернуть его в делегате, используя Multimaps.synchronizedSetMultimap () .

Другой вариант - использовать ComputingMap (также из Гуавы), который представляет собой карту, которая, если значение, возвращаемое при вызове get(Key), не существует, то оно создается там и тогда. ComputingMap s создаются с использованием MapMaker .

Код из вашего вопроса будет примерно:

ConcurrentMap<KEYTYPE, Set<VALUETYPE>> hashMap = new MapMaker()
                 .makeComputingMap(
        new Function<KEYTYPE, VALUETYPE>() {
         public Graph apply(KEYTYPE key) {
           return new HashSet<VALUETYPE>();
         }
       });

Function будет вызываться только тогда, когда вызов get() для определенного ключа в противном случае вернет ноль. Это означает, что вы можете сделать это:

hashMap.get(key).put(value);

безопасно зная, что HashSet<VALUETYPE> создан, если он еще не существует.

MapMaker также имеет значение, поскольку он дает вам контроль над настройкой возвращаемой Карты, позволяя вам указать, например, уровень параллелизма, используя метод concurrencyLevel(). Вы можете найти это полезным:

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

0 голосов
/ 22 марта 2012

Я думаю, что использование java.util.concurrent.ConcurrentSkipListMap и java.util.concurrent.ConcurrentSkipListSet может помочь вам решить проблемы параллелизма.

...