web-dev-qa-db-fra.com

Pourquoi il n'y a pas de ConcurrentHashSet contre ConcurrentHashMap

HashSet est basé sur HashMap.

Si nous regardons l'implémentation de HashSet<E>, tout est géré sous HashMap<E,Object>.

<E> est utilisé comme clé de HashMap.

Et nous savons que HashMap n'est pas thread-safe. C'est pourquoi nous avons ConcurrentHashMap en Java.

Basé sur ceci, je suis confus que pourquoi nous n'avons pas de ConcurrentHashSet qui devrait être basé sur le ConcurrentHashMap?

Y a-t-il autre chose qui me manque? Je dois utiliser Set dans un environnement multithread.

Aussi, si je veux créer ma propre ConcurrentHashSet puis-je y arriver simplement en remplaçant le HashMap par ConcurrentHashMap et en laissant le reste tel quel?

484
Talha Ahmed Khan

Il n'y a pas de type intégré pour ConcurrentHashSet car vous pouvez toujours dériver un ensemble à partir d'une carte. Comme il existe de nombreux types de cartes, vous utilisez une méthode pour produire un ensemble à partir d'une carte donnée (ou classe de carte).

Avant Java 8, vous produisez un hachage simultané défini par une mappe de hachage simultanée à l'aide de Collections.newSetFromMap(map)

Dans Java 8 (indiqué par @Matt), vous pouvez obtenir un affichage de jeu de hachage simultané via ConcurrentHashMap.newKeySet() . C'est un peu plus simple que l'ancien newSetFromMap qui vous demandait de passer dans un objet de carte vide. Mais il est spécifique à ConcurrentHashMap.

Quoi qu'il en soit, les concepteurs Java auraient pu créer une nouvelle interface de jeu chaque fois qu'une nouvelle interface de carte était créée, mais il serait impossible d'appliquer ce modèle lorsque des tiers créent leurs propres cartes. Il est préférable d’avoir les méthodes statiques qui dérivent de nouveaux ensembles; cette approche fonctionne toujours, même lorsque vous créez vos propres implémentations de carte.

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

Avec Guava 15, vous pouvez également utiliser simplement:

Set s = Sets.newConcurrentHashSet();
72
kichik

Comme Ray Toal mentionné, c’est aussi simple que:

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

Il semble que Java fournisse une implémentation Set simultanée avec son ConcurrentSkipListSet . Un SkipList Set est juste un type spécial d'implémentation d'un ensemble. Il implémente toujours les interfaces Serializable, Cloneable, Iterable, Collection, NavigableSet, Set, SortedSet. Cela pourrait fonctionner pour vous si vous n’avez besoin que de l’interface Set.

18
Mike Pone

Comme indiqué par this , le meilleur moyen d'obtenir un HashSet compatible avec la concurrence consiste à utiliser Collections.synchronizedSet()

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

Cela a fonctionné pour moi et je n'ai vu personne vraiment le montrer.

EDIT Ceci est moins efficace que la solution actuellement approuvée, comme le souligne Eugene, car elle englobe simplement votre décor dans un décorateur synchronisé, alors qu'un ConcurrentHashMap implémente réellement concurrence simultanée de bas niveau et il peut sauvegarder votre ensemble tout aussi bien. Donc, merci à M. Stepanenkov de l'avoir précisé.

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

14
Nirro

Vous pouvez utiliser la goyave Sets.newSetFromMap(map) pour en obtenir un. Java 6 a également cette méthode dans 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
MD. Mohiuddin Ahmed

Pourquoi ne pas utiliser: CopyOnWriteArraySet from Java.util.concurrent?

2
Shendor