HashSet is based on HashMap.
HashSet基于HashMap。
If we look at HashSet<E>
implementation, everything is been managed under HashMap<E,Object>
.
如果我们查看HashSet
<E>
is used as a key of HashMap
.
And we know that HashMap
is not thread safe. That is why we have ConcurrentHashMap
in Java.
我们知道HashMap不是线程安全的。这就是为什么我们在Java中有ConcurrentHashMap。
Based on this, I am confused that why we don't have a ConcurrentHashSet which should be based on the ConcurrentHashMap
?
基于此,我很困惑,为什么我们没有一个基于ConcurrentHashMap的ConcurrentHashSet ?
Is there anything else that I am missing? I need to use Set
in a multi-threaded environment.
还有什么是我遗漏的吗?我需要在多线程环境中使用Set。
Also, If I want to create my own ConcurrentHashSet
can I achieve it by just replacing the HashMap
to ConcurrentHashMap
and leaving the rest as is?
另外,如果我想创建自己的ConcurrentHashSet,我是否可以通过将HashMap替换为ConcurrentHashMap并将其余部分保留为is来实现它?
9 个解决方案
#1
406
There's no built in type for ConcurrentHashSet
because you can always derive a set from a map. Since there are many types of maps, you use a method to produce a set from a given map (or map class).
因为你总是可以从地图中导出一个集合,所以没有在类型中建立ConcurrentHashSet。由于有许多类型的映射,您可以使用一个方法从给定的映射(或映射类)生成一个集合。
Prior to Java 8, you produce a concurrent hash set backed by a concurrent hash map, by using Collections.newSetFromMap(map)
在Java 8之前,通过使用Collections.newSetFromMap(map),生成一个并发哈希映射支持的并发散列集。
In Java 8 (pointed out by @Matt), you can get a concurrent hash set view via ConcurrentHashMap.newKeySet()
. This is a bit simpler than the old newSetFromMap
which required you to pass in an empty map object. But it is specific to ConcurrentHashMap
.
在Java 8中(由@Matt指出),您可以通过ConcurrentHashMap.newKeySet()获得一个并发的散列集合视图。这比旧的newSetFromMap要简单一些,它需要您传入一个空的map对象。但它是特定于ConcurrentHashMap。
Anyway, the Java designers could have created a new set interface every time a new map interface was created, but that pattern would be impossible to enforce when third parties create their own maps. It is better to have the static methods that derive new sets; that approach always works, even when you create your own map implementations.
无论如何,Java设计者可以在每次创建新的map接口时创建一个新的set接口,但是当第三方创建自己的映射时,这种模式是不可能执行的。最好有一些静态方法来派生新的集合;这种方法总是有效的,即使您创建了自己的map实现。
#2
74
Set<String> mySet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
#3
#4
16
It looks like Java provides a concurrent Set implementation with its ConcurrentSkipListSet. A SkipList Set is just a special kind of set implementation. It still implements the Serializable, Cloneable, Iterable, Collection, NavigableSet, Set, SortedSet interfaces. This might work for you if you only need the Set interface.
它看起来像Java提供了一个并发集实现和它的ConcurrentSkipListSet。一个SkipList集只是一种特殊的集合实现。它仍然实现Serializable、Cloneable、Iterable、Collection、NavigableSet、Set、SortedSet接口。如果您只需要Set接口,那么这可能对您有用。
#5
12
You can use guava's Sets.newSetFromMap(map)
to get one. Java 6 also has that method in java.util.Collections
您可以使用guava的Sets.newSetFromMap(map)来获得一个。Java 6在Java .util. collection中也有这个方法。
#6
12
Like Ray Toal mentioned it is as easy as:
就像Ray Toal提到的那样简单:
Set<String> myConcurrentSet = ConcurrentHashMap.newKeySet();
#7
10
As pointed by this the best way to obtain a concurrency-able HashSet is by means of Collections.synchronizedSet()
正如这一点所指出的,获得一个可并发的HashSet的最佳方法是通过Collections.synchronizedSet()
Set s = Collections.synchronizedSet(new HashSet(...));
This worked for me and I haven't seen anybody really pointing to it.
这对我很有效,我也没见过有人真的指着它。
EDIT This is less efficient than the currently aproved solution, as Eugene points out, since it just wraps your set into a synchronized decorator, while a ConcurrentHashMap
actually implements low-level concurrency and it can back your Set just as fine. So thanks to Mr. Stepanenkov for making that clear.
正如Eugene指出的那样,编辑这个方法的效率要比当前的解决方案低,因为它只是将您的集合封装到一个同步的decorator中,而ConcurrentHashMap实际上实现了低级别的并发性,并且它可以支持您的设置。因此,感谢Stepanenkov先生让我明白了这一点。
http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedSet-java.util.Set-
http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html # synchronizedSet-java.util.Set -
#8
5
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;
}
}
#9
2
Why not use: CopyOnWriteArraySet from java.util.concurrent?
为什么不使用:java.util.concurrent中的CopyOnWriteArraySet ?
#1
406
There's no built in type for ConcurrentHashSet
because you can always derive a set from a map. Since there are many types of maps, you use a method to produce a set from a given map (or map class).
因为你总是可以从地图中导出一个集合,所以没有在类型中建立ConcurrentHashSet。由于有许多类型的映射,您可以使用一个方法从给定的映射(或映射类)生成一个集合。
Prior to Java 8, you produce a concurrent hash set backed by a concurrent hash map, by using Collections.newSetFromMap(map)
在Java 8之前,通过使用Collections.newSetFromMap(map),生成一个并发哈希映射支持的并发散列集。
In Java 8 (pointed out by @Matt), you can get a concurrent hash set view via ConcurrentHashMap.newKeySet()
. This is a bit simpler than the old newSetFromMap
which required you to pass in an empty map object. But it is specific to ConcurrentHashMap
.
在Java 8中(由@Matt指出),您可以通过ConcurrentHashMap.newKeySet()获得一个并发的散列集合视图。这比旧的newSetFromMap要简单一些,它需要您传入一个空的map对象。但它是特定于ConcurrentHashMap。
Anyway, the Java designers could have created a new set interface every time a new map interface was created, but that pattern would be impossible to enforce when third parties create their own maps. It is better to have the static methods that derive new sets; that approach always works, even when you create your own map implementations.
无论如何,Java设计者可以在每次创建新的map接口时创建一个新的set接口,但是当第三方创建自己的映射时,这种模式是不可能执行的。最好有一些静态方法来派生新的集合;这种方法总是有效的,即使您创建了自己的map实现。
#2
74
Set<String> mySet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
#3
#4
16
It looks like Java provides a concurrent Set implementation with its ConcurrentSkipListSet. A SkipList Set is just a special kind of set implementation. It still implements the Serializable, Cloneable, Iterable, Collection, NavigableSet, Set, SortedSet interfaces. This might work for you if you only need the Set interface.
它看起来像Java提供了一个并发集实现和它的ConcurrentSkipListSet。一个SkipList集只是一种特殊的集合实现。它仍然实现Serializable、Cloneable、Iterable、Collection、NavigableSet、Set、SortedSet接口。如果您只需要Set接口,那么这可能对您有用。
#5
12
You can use guava's Sets.newSetFromMap(map)
to get one. Java 6 also has that method in java.util.Collections
您可以使用guava的Sets.newSetFromMap(map)来获得一个。Java 6在Java .util. collection中也有这个方法。
#6
12
Like Ray Toal mentioned it is as easy as:
就像Ray Toal提到的那样简单:
Set<String> myConcurrentSet = ConcurrentHashMap.newKeySet();
#7
10
As pointed by this the best way to obtain a concurrency-able HashSet is by means of Collections.synchronizedSet()
正如这一点所指出的,获得一个可并发的HashSet的最佳方法是通过Collections.synchronizedSet()
Set s = Collections.synchronizedSet(new HashSet(...));
This worked for me and I haven't seen anybody really pointing to it.
这对我很有效,我也没见过有人真的指着它。
EDIT This is less efficient than the currently aproved solution, as Eugene points out, since it just wraps your set into a synchronized decorator, while a ConcurrentHashMap
actually implements low-level concurrency and it can back your Set just as fine. So thanks to Mr. Stepanenkov for making that clear.
正如Eugene指出的那样,编辑这个方法的效率要比当前的解决方案低,因为它只是将您的集合封装到一个同步的decorator中,而ConcurrentHashMap实际上实现了低级别的并发性,并且它可以支持您的设置。因此,感谢Stepanenkov先生让我明白了这一点。
http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedSet-java.util.Set-
http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html # synchronizedSet-java.util.Set -
#8
5
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;
}
}
#9
2
Why not use: CopyOnWriteArraySet from java.util.concurrent?
为什么不使用:java.util.concurrent中的CopyOnWriteArraySet ?