Java 5 引入的 java.util.concurrent 包含多個高效解決常見併發問題的集合類,卻常被註解與泛型的光芒掩蓋。本文介紹五大核心類,助你擺脫手寫同步代碼的泥潭。
雖非集合,但極大提升代碼可讀性。枚舉涵蓋 NANOSECONDS 至 DAYS,提供轉換方法:TimeUnit.HOURS.toMillis(1)。API 簽名統一使用 (timeout, TimeUnit),徹底擺脫「毫秒霸權」,意圖顯性化。
痛點: 同步 ArrayList 導致讀讀互斥;複製數組成本高。
方案: 寫操作(add/set/remove)複製全新數組,讀操作直接訪問不可變快照,**零同步開銷**。適用場景:事件監聽器列表、配置緩存——頻繁遍歷,極少修改。
List<Listener> listeners = new CopyOnWriteArrayList<>();
// 遍歷無需加鎖
for (Listener l : listeners) l.onEvent(event);
FIFO 隊列,核心特性:空隊列取元素阻塞、滿隊列放元素阻塞。徹底替代手寫 wait()/notifyAll() 的 Guarded Blocks 模式。
ArrayBlockingQueue:有界隊列,支援公平策略(FIFO 獲取鎖),避免線程飢餓。
代碼對比: 生產者 put()、消費者 take(),簡潔無誤。支援 offer/poll(timeout) 避免無限等待。
經典 Bug: if (!map.containsKey(k)) map.put(k, v); 在同步 Map 下仍有競態條件(檢查與放入非原子)。
解決: ConcurrentMap.putIfAbsent(k, v) 原子完成「檢查並放入」。另有 remove(k, v)、replace(k, old, new) 等複合原子操作,ConcurrentHashMap 為高效實現。
特殊的 BlockingQueue:**無內部容量**,put() 必須等待 take(),反之亦然。實現線程間單元素直接交接,語義同 Ada/CSP 的「會合通道」。
代碼結構與 ArrayBlockingQueue 幾乎相同,但更輕量,適合「生產即消費」場景,避免隊列積壓與內存佔用。
五大類覆蓋:時間建模(TimeUnit)、讀多寫少列表(CopyOnWriteArrayList)、生產消費隊列(BlockingQueue)、安全 Map(ConcurrentMap)、直接移交(SynchronousQueue)。下篇將探討鎖、同步器與原子變量等進階工具。