HashSetはHashMapに基づいています。
HashSet<E>
の実装を見ると、すべてがHashMap<E,Object>
の下で管理されています。
<E>
はHashMap
のキーとして使用されます。
そしてHashMap
はスレッドセーフではないことがわかっています。それが、JavaにConcurrentHashMap
がある理由です。
これに基づいて、私はそれを混同しています なぜConcurrentHashMap
に基づくべきConcurrentHashSetを持っていないのですか?
私が欠けているものは他にありますか?マルチスレッド環境ではSet
を使う必要があります。
また、自分でConcurrentHashSet
を作成したい場合は、HashMap
をConcurrentHashMap
に置き換えて残りをそのままにすることで実現できますか?
ConcurrentHashSet
の組み込み型はありません。マップからいつでも 派生 セットを派生させることができるからです。マップには多くの種類があるため、特定のマップ(またはマップクラス)からセットを作成するためのメソッドを使用します。
Java 8より前のバージョンでは、 Collections.newSetFromMap(map)
を使用して、コンカレントハッシュマップを基にしたコンカレントハッシュセットを作成していました。
Java 8(@Mattが指摘)では、 ConcurrentHashMap.newKeySet()
を介して並行ハッシュセット view を取得できます。これは、空のマップオブジェクトを渡す必要がある古いnewSetFromMap
よりも少し単純です。しかし、それはConcurrentHashMap
に固有のものです。
とにかく、Javaデザイナーは新しいマップインターフェースが作成されるたびに新しいセットインターフェースを作成することができましたが、第三者が独自のマップを作成するときそのパターンを強制することは不可能です。新しいセットを派生させる静的メソッドを用意した方が良いでしょう。独自のマップ実装を作成した場合でも、このアプローチは常に有効です。
Set<String> mySet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
Guava 15では、単に使うこともできます。
Set s = Sets.newConcurrentHashSet();
Ray Toal のように簡単です。
Set<String> myConcurrentSet = ConcurrentHashMap.newKeySet();
Javaは ConcurrentSkipListSet を使って並行Set実装を提供しているようです。 SkipList Set は、特別な種類の集合の実装です。それはまだSerializable、Cloneable、Iterable、Collection、NavigableSet、Set、SortedSetインターフェースを実装しています。 Setインタフェースだけが必要な場合、これはうまくいくかもしれません。
this で示されているように、同時実行可能なHashSetを取得する最良の方法はCollections.synchronizedSet()
によるものです。
Set s = Collections.synchronizedSet(new HashSet(...));
これは私のために働きました、そして私は誰もそれを実際に指しているのを見たことがありません。
_ edit _ Eugeneが指摘しているように、これは現在証明されている解決策よりも効率的ではありません。なぜなら、ConcurrentHashMap
name__は実際に低レベルの並行処理を実装し、Setをバックアップできるからです。まあまあです。それを明確にしてくれたStepanenkov氏に感謝します。
http://docs.Oracle.com/javase/8/docs/api/Java/util/Collections.html#synchronizedSet-Java.util.Set- /
入手するにはguavaの Sets.newSetFromMap(map)
を使用できます。 Java 6の 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;
}
}
Java.util.concurrentのCopyOnWriteArraySetを使用しないのはなぜですか。