どうやら、 Javaのユーティリティクラスを使用してスレッドセーフな HashSetインスタンスを取得する方法は2つあります。Collections
私は尋ねます:
- それらはどのように異なりますか?
- どちらが、どのような状況で、他よりも優先されますか?
どうやら、 Javaのユーティリティクラスを使用してスレッドセーフな HashSetインスタンスを取得する方法は2つあります。Collections
私は尋ねます:
あなたが考えているかもしれないことは
Set<Type> set = Collections.newSetFromMap(new ConcurrentHashMap<Type, Boolean>());
これにより、同時更新と読み取りがサポートされます。その Iterator は ConcurrentModicationException をスローしません。一方
Set<Type> set = Collections.synchronizedSet(new HashSet<Type());
より軽量ですが、一度に 1 つのスレッドしかセットにアクセスできません。Iterator を使用する場合はセットを明示的にロックする必要があり、安全な方法で更新しない場合でも CME を取得できます (反復処理中)。
最初のものは、引数として渡されたマップと基本的に同じスレッドセーフとパフォーマンスの保証を持つ Set を返します。マップがスレッドセーフでない場合、セットもそうではありません。API には ConcurrentHashSet がないため、通常、このメソッドを使用して並行マップから並行セットを作成します。
2 番目のものは、すべてのメソッドが同期されている特定のセットにプロキシを返します。
実際には、いくつかの Set スレッドセーフ実装を取得する場合があります。
I. Collections.synchronizedSet(new HashSet
このソリューションはお勧めしません。それ自体はスレッドセーフであり、並行環境では注意して使用する必要があります。見る:
Stack stack = new SynchronizedArrayStack(new ArrayStack());
...
// don't do this in a multi-threaded environment
if (!stack.isEmpty()) {
stack.pop(); // can throw IllegalStateException
}
その結果、クライアント側のロックを使用する必要があります。
synchronized(stack) {
if (!stack.isEmpty()) {
stack.pop();
}
}
Ⅱ.Set インターフェイスの 2 番目の代替並行実装 - CopyOnWriteArraySet。ただし、このソリューションは、多くの検索や挿入が予想されるコンテキストでは使用しないでください。しかし、反復は HashSet よりも要素ごとに O(1) のコストがかかり、一部のアプリケーションでは非常に魅力的な利点が 1 つあります。
III. 最後のものは、CuncurrentHashMap の実装を使用します。
Collections.newSetFromMap(new ConcurrentHashMap<Type, Boolean>());
java.util.concurrent.locks.Lock の実装を使用します。マップは、個別にロックできる部分に分割されるため、同時実行性が向上します。したがって、最後の 2 つのオプションから選択する必要があります。
Thera には、ソート済みセットの実装のオプションもあります。Java Generics and Collections
の章を読むことをお勧めします11.5 Collections and Thread Safety
。
あなたは間違っています。newSetFromMap() はスレッド セーフを提供しません。Javadoc をもう一度確認してください。
これら 2 つのメソッドの入力タイプが異なるという小さな問題もあります。