1)CopyOnWriteArraySet
は非常に単純な実装です。基本的には配列に要素のリストがあり、リストを変更すると配列がコピーされます。この時点で実行されている反復とその他のアクセスは、古いアレイで続行され、読み取りと書き込みの間の同期の必要性を回避します(ただし、書き込み自体は同期する必要があります)。contains()
配列は線形時間で検索されるため、通常は高速なセット操作(特に)はここではかなり遅くなります。
これは、頻繁に読み込まれ(繰り返し)、めったに変更されない非常に小さなセットにのみ使用してください。(Swingsリスナーセットは一例ですが、実際にはセットではなく、EDTからのみ使用する必要があります。)
2)Collections.synchronizedSet
元のセットの各メソッドの周りに同期ブロックをラップするだけです。元のセットに直接アクセスしないでください。つまり、セットの2つのメソッドを同時に実行することはできません(一方は他方が完了するまでブロックされます)。これはスレッドセーフですが、複数のスレッドが実際にセットを使用している場合、同時実行性はありません。イテレータを使用する場合、イテレータの呼び出し間でセットを変更するときにConcurrentModificationExceptionsを回避するために、通常は引き続き外部と同期する必要があります。パフォーマンスは、元のセットのパフォーマンスに似ています(ただし、同期オーバーヘッドがあり、同時に使用するとブロックされます)。
同時実行性が低く、すべての変更が他のスレッドにすぐに見えるようにしたい場合に、これを使用します。
3)ConcurrentSkipListSet
は並行SortedSet
実装であり、O(log n)で最も基本的な演算が行われます。イテレータが作成されてからの変更について、反復によって通知される場合と通知されない場合とで、追加/削除と読み取り/反復を同時に実行できます。バルク操作は単純に複数の単一の呼び出しであり、アトミックではありません。他のスレッドはそれらの一部のみを監視する場合があります。
明らかに、これは、要素に全体的な順序がある場合にのみ使用できます。これは、(O(log n)のため)大きすぎないセットに対して、同時実行性の高い状況の理想的な候補のように見えます。
4)ConcurrentHashMap
(およびそれから導出されたセット)の場合:ここで最も基本的なオプションはhashCode()
、H(Map)のように、O(1)の(平均して、適切で高速な場合)です(ただし、O(n)に縮退する可能性があります)。 HashSet。書き込みの同時実行には制限があります(テーブルはパーティション化されており、書き込みアクセスは必要なパーティションで同期されます)一方で、読み取りアクセスはそれ自体と書き込みスレッドに完全に並行します(ただし、現在行われている変更の結果はまだ表示されない場合があります)書かれた)。イテレータは、作成されてからの変更を確認する場合としない場合があり、一括操作はアトミックではありません。サイズ変更が遅い(HashMap / HashSetの場合と同様)ため、作成時に必要なサイズを見積もることでこれを回避しようとします(3/4フルになるとサイズ変更されるため、約1/3をさらに使用します)。
大きなセットと適切な(そして高速な)ハッシュ関数があり、マップを作成する前にセットのサイズと必要な同時実行性を推定できる場合に、これを使用します。
5)ここで使用できる他の並行マップ実装はありますか?