並發集合

概述

Java 提供了多種執行緒安全的集合類,用於在多執行緒環境下安全地操作資料。

執行緒安全選項比較

類別執行緒安全說明
ArrayList非同步,效能最好
Vector同步,效能較差,已過時
Collections.synchronizedList()包裝器方式
CopyOnWriteArrayList讀寫分離,適合讀多寫少

BlockingQueue 阻塞隊列

BlockingQueue 是一個支援阻塞操作的 FIFO 佇列。

不需要關心何時 Block Thread、何時 Wake Thread,一切交由 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 允許多個執行緒同時存取不同的 segment,大幅提升並發效能。與 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 系列]

參考資源