Por qué no hay ConcurrentHashSet contra ConcurrentHashMap

HashSet se basa en HashMap.

Si observamos la implementación de HashSet , todo se gestiona bajo HashMap .

se utiliza como una clave de HashMap .

Y sabemos que HashMap no es seguro para subprocesos. Es por eso que tenemos ConcurrentHashMap en Java.

En base a esto, estoy confundido acerca de por qué no tenemos un ConcurrentHashSet que debería basarse en el ConcurrentHashMap ?

¿Hay algo más que me estoy perdiendo? Necesito usar Set en un entorno multihilo.

Además, si quiero crear mi propio ConcurrentHashSet ¿puedo lograrlo simplemente reemplazando el HashMap por ConcurrentHashMap y dejando el rest tal como está?

No existe un tipo integrado para ConcurrentHashSet porque siempre puede derivar un conjunto de un mapa. Como hay muchos tipos de mapas, utiliza un método para producir un conjunto a partir de un mapa determinado (o clase de mapa).

Antes de Java 8, produce un conjunto hash simultáneo respaldado por un mapa hash concurrente, utilizando Collections.newSetFromMap(map)

En Java 8 (señalado por @Matt), puede obtener una vista de conjunto de hash concurrente a través de ConcurrentHashMap.newKeySet() . Esto es un poco más simple que el antiguo newSetFromMap que requería que newSetFromMap un objeto de mapa vacío. Pero es específico de ConcurrentHashMap .

De todos modos, los diseñadores de Java podrían haber creado una nueva interfaz de conjunto cada vez que se creó una nueva interfaz de mapa, pero ese patrón sería imposible de aplicar cuando los terceros crean sus propios mapas. Es mejor tener los métodos estáticos que derivan nuevos conjuntos; ese enfoque siempre funciona, incluso cuando crea sus propias implementaciones de mapas.

 Set mySet = Collections.newSetFromMap(new ConcurrentHashMap()); 

Con Guava 15 también puede simplemente usar:

 Set s = Sets.newConcurrentHashSet(); 

Como Ray Toal mencionó, es tan fácil como:

 Set myConcurrentSet = ConcurrentHashMap.newKeySet(); 

Parece que Java proporciona una implementación de Conjunto concurrente con su ConcurrentSkipListSet . Un conjunto SkipList es solo un tipo especial de implementación de conjunto. Todavía implementa las interfaces Serializable, Cloneable, Iterable, Collection, NavigableSet, Set, SortedSet. Esto podría funcionar para usted si solo necesita la interfaz Establecer.

Puede usar Sets.newSetFromMap(map) para obtener uno. Java 6 también tiene ese método en java.util.Collections

Como señala este, la mejor forma de obtener un HashSet compatible con concurrencia es mediante Collections.synchronizedSet()

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

Esto funcionó para mí y no he visto a nadie realmente señalando.

EDITAR Esto es menos eficiente que la solución aprobada actualmente, como señala Eugene, ya que simplemente envuelve tu decorado en un decorador sincronizado, mientras que un ConcurrentHashMap realmente implementa una ConcurrentHashMap bajo nivel y puede respaldar tu Set igual de bien. Así que gracias al Sr. Stepanenkov por dejar eso en claro.

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

 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 extends AbstractSet implements Set{ private final ConcurrentMap theMap; private static final Object dummy = new Object(); public ConcurrentHashSet(){ theMap = new ConcurrentHashMap(); } @Override public int size() { return theMap.size(); } @Override public Iterator 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; } } 

¿Por qué no usar: CopyOnWriteArraySet de java.util.concurrent?