it-swarm.com.de

Warum gibt es kein ConcurrentHashSet gegen ConcurrentHashMap

HashSet basiert auf HashMap.

Wenn wir uns die Implementierung von HashSet<E> ansehen, wird alles unter HashMap<E,Object> verwaltet.

<E> wird als Schlüssel für HashMap verwendet.

Und wir wissen, dass HashMap nicht threadsicher ist. Deshalb haben wir ConcurrentHashMap in Java.

Aufgrund dessen bin ich verwirrt darüber, dass warum wir kein ConcurrentHashSet haben, das auf dem ConcurrentHashMap basieren sollte?

Fehlt mir noch etwas? Ich muss Set in einer Umgebung mit mehreren Threads verwenden.

Wenn ich mein eigenes ConcurrentHashSet erstellen möchte, kann ich es dann erreichen, indem ich HashMap durch ConcurrentHashMap ersetze und den Rest so lasse, wie er ist?

484

Es gibt keinen eingebauten Typ für ConcurrentHashSet, da Sie jederzeit einen Satz von einer Karte ableiten können . Da es viele Arten von Karten gibt, verwenden Sie eine Methode, um einen Satz aus einer bestimmten Karte (oder Kartenklasse) zu erstellen.

Vor Java 8 erstellen Sie mithilfe von Collections.newSetFromMap(map) ein Concurrent-Hash-Set, das von einer Concurrent-Hash-Map unterstützt wird

In Java 8 (von @Matt hervorgehoben) können Sie eine gleichzeitige Hash-Menge anzeigen über ConcurrentHashMap.newKeySet() . Dies ist etwas einfacher als das alte newSetFromMap, bei dem Sie ein leeres Kartenobjekt übergeben mussten. Aber es ist spezifisch für ConcurrentHashMap.

Wie auch immer, die Entwickler von Java hätten jedes Mal, wenn eine neue Kartenschnittstelle erstellt wurde, eine neue Set-Schnittstelle erstellen können, aber dieses Muster wäre unmöglich durchzusetzen, wenn Dritte ihre eigenen Karten erstellen. Es ist besser, die statischen Methoden zu haben, die neue Mengen ableiten. Dieser Ansatz funktioniert immer, auch wenn Sie eigene Kartenimplementierungen erstellen.

535
Ray Toal
Set<String> mySet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
95
Serge Mask

Mit Guave 15 können Sie auch einfach verwenden:

Set s = Sets.newConcurrentHashSet();
72
kichik

Wie Ray Toal erwähnt ist es so einfach wie:

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

Es sieht so aus, als ob Java eine gleichzeitige Set-Implementierung mit ConcurrentSkipListSet bereitstellt. Ein SkipList Set ist nur eine spezielle Art von Set-Implementierung. Es implementiert weiterhin die Schnittstellen Serializable, Cloneable, Iterable, Collection, NavigableSet, Set und SortedSet. Dies könnte für Sie funktionieren, wenn Sie nur die Set-Schnittstelle benötigen.

18
Mike Pone

Wie durch this gezeigt, ist der beste Weg, ein paralleles HashSet zu erhalten, mittels Collections.synchronizedSet()

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

Das hat bei mir funktioniert und ich habe niemanden gesehen, der wirklich darauf hingewiesen hat.

EDIT Dies ist weniger effizient als die derzeit empfohlene Lösung, wie Eugene betont, da es Ihr Set nur in einen synchronisierten Dekorateur einwickelt, während ein ConcurrentHashMap implementiert tatsächlich eine Nebenläufigkeit auf niedriger Ebene und kann Ihr Set genauso gut unterstützen. Vielen Dank an Herrn Stepanenkov für die Klarstellung.

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

14
Nirro

Sie können guava's Sets.newSetFromMap(map) verwenden, um eine zu erhalten. Java 6 hat diese Methode auch in Java.util.Collections

12
Bozho
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;
   }
}
5

Warum nicht: CopyOnWriteArraySet aus Java.util.concurrent verwenden?

2
Shendor