java - ¿Por qué no hay Hashetet Concurrente contra HashMap Concurrente?
collections concurrency (9)
HashSet se basa en HashMap.
Si observamos la implementación de HashSet<E>
, todo se gestiona bajo HashMap<E,Object>
.
<E>
se utiliza como 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 de que ¿por qué no tenemos un Conjunto de Hash Concurrente que debería estar basado en el ConcurrentHashMap
?
¿Hay algo más que me esté perdiendo? Necesito usar Set
en un entorno de subprocesos múltiples.
Además, si quiero crear mi propio conjunto de ConcurrentHashSet
¿puedo lograrlo simplemente reemplazando el HashMap
de HashMap
al HashMap
de elementos ConcurrentHashMap
y dejando el resto tal como está?
¿Por qué no usar: CopyOnWriteArraySet de java.util.concurrent?
Como mencionó Ray Toal , es tan fácil como:
Set<String> myConcurrentSet = ConcurrentHashMap.newKeySet();
Como se señala en this la mejor manera de obtener un HashSet compatible con la concurrencia es mediante Collections.synchronizedSet()
Set s = Collections.synchronizedSet(new HashSet(...));
Esto funcionó para mí y no he visto a nadie que realmente lo señale.
EDITAR Esto es menos eficiente que la solución actualmente aprobada, como señala Eugene, ya que simplemente envuelve su conjunto en un decorador sincronizado, mientras que un ConcurrentHashMap
realmente implementa la ConcurrentHashMap
bajo nivel y puede respaldar su conjunto tan bien. Así que gracias al Sr. Stepanenkov por aclararlo.
http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedSet-java.util.Set-
Con Guava 15 también puedes simplemente usar:
Set s = Sets.newConcurrentHashSet();
No hay 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 dado (o clase de mapa).
Antes de Java 8, produce un conjunto de hash simultáneo respaldado por un mapa de 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 pasara 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 creara una nueva interfaz de mapa, pero ese patrón sería imposible de aplicar cuando 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.
Parece que Java proporciona una implementación de conjunto concurrente con su docs.oracle.com/javase/7/docs/api/java/util/concurrent/… . Un conjunto SkipList es solo un tipo especial de implementación de conjuntos. Todavía implementa las interfaces Serializable, Cloneable, Iterable, Collection, NavigableSet, Set, SortedSet. Esto podría funcionar para usted si solo necesita la interfaz Set.
Puede usar guava''s Sets.newSetFromMap(map)
para obtener uno. Java 6 también tiene ese método en Collections.newSetFromMap(map)
Set<String> mySet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
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;
}
}