web-dev-qa-db-ja.com

ConcurrentHashMapに対してConcurrentHashSetがない理由

HashSetはHashMapに基づいています。

HashSet<E>の実装を見ると、すべてがHashMap<E,Object>の下で管理されています。

<E>HashMapのキーとして使用されます。

そしてHashMapはスレッドセーフではないことがわかっています。それが、JavaにConcurrentHashMapがある理由です。

これに基づいて、私はそれを混同しています なぜConcurrentHashMapに基づくべきConcurrentHashSetを持っていないのですか?

私が欠けているものは他にありますか?マルチスレッド環境ではSetを使う必要があります。

また、自分でConcurrentHashSetを作成したい場合は、HashMapConcurrentHashMapに置き換えて残りをそのままにすることで実現できますか?

462

ConcurrentHashSetの組み込み型はありません。マップからいつでも 派生 セットを派生させることができるからです。マップには多くの種類があるため、特定のマップ(またはマップクラス)からセットを作成するためのメソッドを使用します。

Java 8より前のバージョンでは、 Collections.newSetFromMap(map) を使用して、コンカレントハッシュマップを基にしたコンカレントハッシュセットを作成していました。

Java 8(@Mattが指摘)では、 ConcurrentHashMap.newKeySet() を介して並行ハッシュセット view を取得できます。これは、空のマップオブジェクトを渡す必要がある古いnewSetFromMapよりも少し単純です。しかし、それはConcurrentHashMapに固有のものです。

とにかく、Javaデザイナーは新しいマップインターフェースが作成されるたびに新しいセットインターフェースを作成することができましたが、第三者が独自のマップを作成するときそのパターンを強制することは不可能です。新しいセットを派生させる静的メソッドを用意した方が良いでしょう。独自のマップ実装を作成した場合でも、このアプローチは常に有効です。

519
Ray Toal
Set<String> mySet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
92
Serge Mask

Guava 15では、単に使うこともできます。

Set s = Sets.newConcurrentHashSet();
70
kichik

Ray Toal のように簡単です。

Set<String> myConcurrentSet = ConcurrentHashMap.newKeySet();
24
BullyWiiPlaza

Javaは ConcurrentSkipListSet を使って並行Set実装を提供しているようです。 SkipList Set は、特別な種類の集合の実装です。それはまだSerializable、Cloneable、Iterable、Collection、NavigableSet、Set、SortedSetインターフェースを実装しています。 Setインタフェースだけが必要な場合、これはうまくいくかもしれません。

17
Mike Pone

this で示されているように、同時実行可能なHashSetを取得する最良の方法はCollections.synchronizedSet()によるものです。

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

これは私のために働きました、そして私は誰もそれを実際に指しているのを見たことがありません。

_ edit _ Eugeneが指摘しているように、これは現在証明されている解決策よりも効率的ではありません。なぜなら、ConcurrentHashMapname__は実際に低レベルの並行処理を実装し、Setをバックアップできるからです。まあまあです。それを明確にしてくれたStepanenkov氏に感謝します。

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

13
Nirro

入手するにはguavaの Sets.newSetFromMap(map) を使用できます。 Java 6の Java.util.Collections にもそのメソッドがあります。

12
Bozho
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;
   }
}
5

Java.util.concurrentのCopyOnWriteArraySetを使用しないのはなぜですか。

2
Shendor