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?
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.
Set<String> mySet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
Avec Guava 15, vous pouvez également utiliser simplement:
Set s = Sets.newConcurrentHashSet();
Comme Ray Toal mentionné, c’est aussi simple que:
Set<String> myConcurrentSet = ConcurrentHashMap.newKeySet();
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.
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-
Vous pouvez utiliser la goyave Sets.newSetFromMap(map)
pour en obtenir un. Java 6 a également cette méthode dans Java.util.Collections
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;
}
}
Pourquoi ne pas utiliser: CopyOnWriteArraySet from Java.util.concurrent?