Почему нет ConcurrentHashSet против ConcurrentHashMap

HashSet основан на HashMap.

Если мы посмотрим на реализацию HashSet<E>, все будет управляться в HashMap<E,Object>.

<E> используется как ключ HashMap.

И мы знаем, что HashMap не является потокобезопасным. Вот почему мы имеем ConcurrentHashMap в Java.

Исходя из этого, я смущен тем, что почему у нас нет ConcurrentHashSet, который должен основываться на ConcurrentHashMap?

Есть ли что-то еще, что мне не хватает? Мне нужно использовать Set в многопоточной среде.

Кроме того, если я хочу создать свой собственный ConcurrentHashSet, могу ли я его достичь, просто заменив HashMap на ConcurrentHashMap и оставив все как есть?

Ответ 1

Нет встроенного типа для ConcurrentHashSet, потому что вы всегда можете получить набор из карты. Поскольку существует множество типов карт, вы используете метод для создания набора из заданной карты (или класса карты).

До Java 8 вы создаете параллельный хеш-набор, поддерживаемый параллельной картой хэша, используя Collections.newSetFromMap(map)

В Java 8 (отмеченном @Matt) вы можете получить одновременное представление хеш-набора через ConcurrentHashMap.newKeySet(). Это немного проще, чем старый newSetFromMap, который потребовал от вас передать пустой объект карты. Но он специфичен для ConcurrentHashMap.

В любом случае разработчики Java могли бы создать новый настраиваемый интерфейс каждый раз, когда был создан новый интерфейс карты, но этот шаблон будет невозможно обеспечить, когда сторонние лица создают свои собственные карты. Лучше иметь статические методы, которые производят новые множества; этот подход всегда работает, даже когда вы создаете свои собственные реализации карт.

Ответ 2

Set<String> mySet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());

Ответ 3

С помощью Guava 15 вы также можете просто использовать:

Set s = Sets.newConcurrentHashSet();

Ответ 4

Похоже, Java предоставляет параллельную реализацию Set с ConcurrentSkipListSet. A Набор SkipList - это особый вид реализации набора. Он по-прежнему реализует интерфейсы Serializable, Cloneable, Iterable, Collection, NavigableSet, Set, SortedSet. Это может сработать для вас, если вам нужен только интерфейс Set.

Ответ 6

Как указано this, лучший способ получить concurrency -able HashSet - с помощью Collections.synchronizedSet()

Set s = Collections.synchronizedSet(new HashSet(...));

Это сработало для меня, и я не видел, чтобы кто-то действительно указывал на это.

РЕДАКТИРОВАТЬ Это менее эффективно, чем в настоящее время аппроксимированное решение, как отмечает Юджин, поскольку он просто переносит ваш набор в синхронизированный декоратор, а ConcurrentHashMap фактически реализует низкоуровневый concurrency и он может поддерживать ваш набор так же хорошо. Так спасибо господину Степаненкову за это ясно.

http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedSet-java.util.Set-

Ответ 7

Как Ray Toal упомянул, что это так же просто, как:

Set<String> myConcurrentSet = ConcurrentHashMap.newKeySet();

Ответ 8

import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;


public class ConcurrentHashSet<E> extends AbstractSet<E> implements Set<E>{
   private final ConcurrentMap<E, Object> theMap;

   private static final Object dummy = new Object();

   public ConcurrentHashSet(){
      theMap = new ConcurrentHashMap<E, Object>();
   }

   @Override
   public int size() {
      return theMap.size();
   }

   @Override
   public Iterator<E> iterator(){
      return theMap.keySet().iterator();
   }

   @Override
   public boolean isEmpty(){
      return theMap.isEmpty();
   }

   @Override
   public boolean add(final E o){
      return theMap.put(o, ConcurrentHashSet.dummy) == null;
   }

   @Override
   public boolean contains(final Object o){
      return theMap.containsKey(o);
   }

   @Override
   public void clear(){
      theMap.clear();
   }

   @Override
   public boolean remove(final Object o){
      return theMap.remove(o) == ConcurrentHashSet.dummy;
   }

   public boolean addIfAbsent(final E o){
      Object obj = theMap.putIfAbsent(o, ConcurrentHashSet.dummy);
      return obj == null;
   }
}

Ответ 9

Почему бы не использовать: CopyOnWriteArraySet из java.util.concurrent?