並行コレクション

概要

Java はマルチスレッド環境かんきょう安全あんぜんにデータを操作そうさするための様々さまざまなスレッドセーフなコレクションクラスを提供ていきょうしている。

スレッドセーフオプション比較

クラススレッドセーフ説明せつめい
ArrayListいいえ非同期ひどうき最高さいこう性能せいのう
Vectorはい同期どうき性能せいのうひくい、非推奨ひすいしょう
Collections.synchronizedList()はいラッパー方式ほうしき
CopyOnWriteArrayListはい分離ぶんりおおすくない場合ばあいてきする

BlockingQueue ブロッキングキュー

BlockingQueue はブロッキング操作そうさ対応たいおうする FIFO キュー。

いつスレッドをブロックするか、いつスレッドを起床きしょうさせるかをにする必要ひつようがない。すべて BlockingQueue が処理しょりする。

実装クラス

実装じっそうクラス説明せつめい
ArrayBlockingQueue有界ゆうかいブロッキングキュー、配列はいれつベース
LinkedBlockingQueue有界ゆうかいブロッキングキュー、リンクリストベース
DelayQueue遅延ちえん無界むかい優先度ゆうせんどブロッキングキュー
PriorityBlockingQueue優先度ゆうせんどソート対応たいおう無界むかいブロッキングキュー
SynchronousQueueバッファなしの待機たいきキュー、要素ようそ格納かくのうしないブロッキングキュー

操作メソッド

タイプ例外れいがいスロー特殊とくしゅブロッキングタイムアウト
挿入そうにゅうadd(e)offer(e)put(e)offer(e, time, unit)
削除さくじょremove()poll()take()poll(time, unit)
検査けんさelement()peek()--

動作どうさ説明せつめい

  • 例外れいがいスロー
    • キューが満杯まんぱいときadd()IllegalStateException: Queue full をスロー
    • キューがからときremove()NoSuchElementException をスロー
  • 特殊とくしゅ
    • offer() 成功せいこうtrue失敗しっぱいfalseかえ
    • poll() 成功せいこう要素ようそ失敗しっぱいnullかえ
  • ブロッキング
    • キューが満杯まんぱいときput()きができるまでブロック
    • キューがからときtake()要素ようそができるまでブロック
  • タイムアウト
    • 指定してい時間じかんブロック、タイムアウトで終了しゅうりょう

ConcurrentHashMap

ConcurrentHashMap はスレッドセーフな HashMap 実装じっそう

特性とくせい説明せつめい
実装じっそう方式ほうしきCAS + Synchronized(内部ないぶ実装じっそうでロックの粒度りゅうど最小さいしょう維持いじ
デフォルトセグメントすう16 segments
デフォルト容量ようりょう16
負荷ふか係数けいすう0.75
ConcurrentHashMap は複数ふくすうのスレッドがことなるセグメントに同時どうじアクセスできるため、並行へいこう性能せいのう大幅おおはば向上こうじょうする。Hashtable とはことなり、Map 全体ぜんたいをロックしない。
ConcurrentHashMapExample.java
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key1", 1);
map.putIfAbsent("key2", 2);  // アトミック操作
map.compute("key1", (k, v) -> v + 1);  // アトミック操作

CopyOnWriteArrayList

CopyOnWriteArrayList はスレッドセーフな ArrayList 変種へんしゅ

特性とくせい説明せつめい
操作そうさロック不要ふよう直接ちょくせつ
操作そうさもと配列はいれつをコピーし、コピーを修正しゅうせいしてから置換ちかん
適用てきようシーンおおすくない
操作そうさ配列はいれつ全体ぜんたいをコピーする必要ひつようがあり、オーバーヘッドがおおきい。おおすくないシーンにてきし、みが頻繁ひんぱんなシーンにはてきさない。
CopyOnWriteArrayListExample.java
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("item1");
list.add("item2");

// イテレーション中に安全に修正可能
for (String item : list) {
    System.out.println(item);
    list.add("newItem");  // ConcurrentModificationException をスローしない
}

スレッドセーフなデータ構造

以下いか一般的いっぱんてき並行へいこうデータ構造こうぞう

データ構造こうぞう説明せつめい
ConcurrentHashMap並行へいこう HashMap
ConcurrentLinkedQueue無界むかいブロッキングキュー
ConcurrentLinkedDeque無界むかいブロッキング両端りょうたんキュー
LinkedBlockingQueue有界ゆうかいブロッキングキュー
ArrayBlockingQueue有界ゆうかいブロッキングキュー

Lock-Free データ構造

技術原理

Lock-Free データ構造こうぞうおもに CAS(Compare and Swap)操作そうさ使用しようして実装じっそうされる。

実装例

  • Lock-Free Stack
  • Lock-Free LinkedList
  • Disruptor
  • Ring Buffer
  • ConcurrentLinkedQueue
  • ConcurrentLinkedDeque
  • AtomicXXX クラス(AtomicInteger, AtomicLong, AtomicReference など)
AtomicIntegerExample.java
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet();  // アトミックインクリメント
counter.compareAndSet(1, 2);  // CAS 操作

ArrayList vs Vector

特性とくせいArrayListVector
スレッドセーフいいえはい(同期どうき
性能せいのうわる
拡張かくちょう戦略せんりゃく通常つうじょう 50% 増加ぞうかまたは倍増ばいぞう倍増ばいぞう増加ぞうかりつ指定してい可能かのう
推奨すいしょう一般いっぱんシーンで推奨すいしょう非推奨ひすいしょう過去かこのクラス

Collection のスレッドセーフ選択

  flowchart TB
    Q{スレッドセーフが必要?}
    Q -->|いいえ| A[ArrayList / HashMap]
    Q -->|はい| S{読み書き比率?}
    S -->|読み多く書き少ない| C[CopyOnWriteArrayList]
    S -->|読み書き均衡| CH[ConcurrentHashMap / Collections.synchronized*]
    S -->|ブロッキング必要| B[BlockingQueue 系列]

参考リソース