Javaのスレッドセーフなコレクションについて調べてみたら、複雑過ぎて頭がクラクラしてきた。
けど、まとめていく過程で自分なりに理解できた気がする。
各クラスのメソッドについてはあまり記載してない。
レガシークラス
古いクラスなので基本は使わない。
レガシークラス | 対応するクラス |
---|---|
Vector | ArrayList |
Stack | LinkedList |
HashTable | HashMap |
コレクション インタフェース
java.util直下のインタフェース
インタフェース | 説明 | 補足 |
---|---|---|
java.util.List | リスト | 順序付けされたコレクション |
java.util.Queue | キュー | JavaではFIFOとは限らない。 |
java.util.Deque | 両端キュー | デックと読む。デキューではない。Double Ended Queueの略。 |
java.util.Set | セット | 重複した要素を許可しないコレクション |
java.util.Map | マップ | キーと値のペアを扱うコレクション |
java.util.SortedSet | キー順にソートされたSet | Setのサブインタフェース |
java.util.SortedMap | キー順にソートされたMap | Mapのサブインタフェース |
java.util.NavigableSet | 指定したキーに近い内容を取得することができるSet | SortedSetのサブインタフェース |
java.util.NavigableMap | 指定したキーに近い内容を取得することができるMap | SortedMapのサブインタフェース |
java.util.concurrent.BlockingQueue
Queueのサブインターフェース。
BlockingQueueの実装は容量を制限している場合がある。
BlockingQueueのメソッドのサマリー
例外のスロー | 特殊な値 | ブロック | タイム・アウト | |
---|---|---|---|---|
挿入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
削除 | remove() | poll() | take() | poll(time, unit) |
検査 | element() | peek() | 適用外 | 適用外 |
BlockingQueue (Java Platform SE 8) より
- add(e), remove(), element()は処理できないと例外発生する
- offer(e)
要素追加。容量が空いてなければfalseを返す。 - put(e)
要素追加。容量が空いてなければ待機。 - poll()
キューの先頭を取得して削除。キューが空の場合はnullを返す。 - take()
キューの先頭を取得して削除。必要に応じて、要素が利用可能になるまで待機。 - peek()
キューの先頭を取得するが、削除しない。キューが空の場合はnullを返す。
java.util.concurrent.BlockingDeque
BlockingQueueのサブインターフェース。
両端キュー
java.util.concurrent.TransferQueue (1.7)
BlockingQueueのサブインターフェース。
java.util.concurrent.ConcurrentMap
スレッドの安全性と原子性の保証を提供するMapです。
java.util.concurrent.ConcurrentSetはない
java.util.concurrent.ConcurrentNavigableMap
NavigableMapオペレーションをサポートするConcurrentMap。
指定した値にもっとも近い内容を取得することができる
java.util.concurrent.ConcurrentNavigableSetはない
同期化、並列化されていないコレクション実装
- 「java.util」の直下に所属するコレクションの実装
- スレッドセーフではない
- イテレート中に(主に別スレッドで)操作を行った場合、ConcurrentModificationException が投げられる。
toStringなど、内部でイテレート処理が走ることがあるので注意。
インタフェース | ハッシュ表 | サイズ変更可能な配列 | バランス・ツリー | リンク・リスト | ハッシュ表+リンク・リスト |
---|---|---|---|---|---|
Set | HashSet | TreeSet | LinkedHashSet | ||
List | ArrayList | LinkedList | |||
Deque | ArrayDeque | LinkedList | |||
Map | HashMap | TreeMap | LinkedHashMap |
java.util直下の実装
クラス名 | 補足 |
---|---|
java.util.ArrayList | 配列実装List |
java.util.LinkedList | リンクノードに基づくList。List、Queue、Dequeインタフェースを実装 |
java.util.HashSet | ハッシュテーブル実装Set |
java.util.HashMap | ハッシュテーブル実装Map |
java.util.TreeSet | バランスツリー実装のSet。NavigableSetを実装。 |
java.util.TreeMap | バランスツリー実装Map NavigableMapを実装。 |
java.util.PriorityQueue | 同期化されてないので注意。|スレッドセーフである必要が有る場合はPriorityBlockingQueueクラスを使用。 |
同期化コレクション
- 「Vector」や「Hashtable」や「Collections.synchronizedXXX()による同期化ラッパー」のこと。
- 要素の内容の変更があるようなメソッドは、全てsynchronizedになっているのが特徴。
- 同期コレクションはロックによりコレクションの操作を1スレッドに限定
- イテレート中に操作を行った場合、ConcurrentModificationException が投げられるのはラッパー使用前と同様。
java.util.Collections.synchronizedXXX()による同期化ラッパー
指定されたコレクションに連動する同期(スレッドセーフな)コレクションを返す。
例:
List<String> list = Collections.synchronizedList(new ArrayList<String>()); Set<String> set = Collections.synchronizedSet(new HashSet<String>()); Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());
並行コレクション(並列コレクション)
- 「CopyOnWriteArrayList」や「ConcurrentHashMap」などJavaSE5.0より加わった「java.util.concurrent」以下にあるコレクションのこと。
- マルチスレッドから同時操作できるように設計
- 複合アクションに対応している。
- イテレーション時にConcurrentModificationExceptionを発生させない。
CopyOnWriteArrayList
Copy-on-Write実装によるスレッドセーフList
Listの変更があった場合、新たなコピーを作成。
これによりアクセス時の同期が不要なる。
イテレート処理はイテレータが作られた時の状態で走査され、別スレッドからの変更の影響は受けない。
CopyOnWriteArraySet
Copy-on-Write実装によるスレッドセーフSet
ConcurrentHashMap
並行ハッシュテーブル実装によるMap
ConcurrentHashSetはない
ConcurrentHashMap.KeySetViewメソッドを使う。
ConcurrentSkipListMap
ConcurrentNavigableMapを実装したMap。
指定した値に近いキーを拾ってくることもできる。
ConcurrentSkipListSet
NavigableSetを実装したSet。
指定した値に近いキーを拾ってくることもできる。
キュー関連のまとめ
注意:容量指定がなくてもメモリがなければ例外は発生する。
クラス | 方向 | 容量制限 | ブロッキング | 主な実装インタフェース |
---|---|---|---|---|
ArrayBlockingQueue | FIFO | あり | ブロッキング | BlockingQueue |
LinkedBlockingQueue | FIFO | 任意 | ブロッキング | BlockingQueue |
PriorityBlockingQueue | 優先順位付きFIFO | なし | ブロッキング | BlockingQueue |
DelayQueue | FIFO | なし | ブロッキング | BlockingQueue |
SynchronousQueue | FIFO | - | ブロッキング | BlockingQueue |
LinkedBlockingDeque | 双方向 | 任意 | ブロッキング | BlockingDeque |
ConcurrentLinkedQueue | FIFO | なし | ノンブロッキング | Queue |
LinkedTransferQueue | FIFO | なし | ブロッキング or ノンブロッキング両方 | TransferQueue |
ArrayBlockingQueue
生成時に容量を指定。
LinkedBlockingQueue
生成時に容量を指定しても、しなくてもいい。
PriorityBlockingQueue
DelayQueue
遅延時間が経過後にのみ、要素を取得できる。
SynchronousQueue
値の追加は、値の取得が行われるまでブロックする。
値の取得は、値の追加が行われるまでブロックする。
- 同期キューには、内部容量がまったくありません。
- 要素が存在するのは削除しようとするときだけなので、同期キューで peek を実行することはできません。
- 別のスレッドが削除を試みていないかぎり、どのメソッドを使用しても要素を挿入することはできません。
- 反復するものが存在しないため、反復は実行できません。
LinkedBlockingDeque
生成時に容量を指定しても、しなくてもいい。
ConcurrentLinkedQueue
ノンブロッキング。