Java 5 引入 java.util.concurrent 套件(源自 Doug Lea 的 JSR-166),為多線程開發提供工業級並發資料結構。本文深度解析新增的 Queue 介面族系、ConcurrentMap、CopyOnWrite 集合,助您構建高效、安全的並發應用。
新增 java.util.Queue<E> 介面,定義核心操作:
| 方法 | 行為 | 異常處理 |
|---|---|---|
offer(E e) | 插入元素 (容量受限時不拋異常) | 失敗回傳 false |
remove() | 移除並回傳頭部元素 | 空佇列拋 NoSuchElementException |
poll() | 移除並回傳頭部元素 | 空佇列回傳 null |
element() | 檢視頭部元素 (不移除) | 空佇列拋 NoSuchElementException |
peek() | 檢視頭部元素 (不移除) | 空佇列回傳 null |
設計哲學:offer/poll/peek 為「友善版」,適合生產環境;add/remove/element 為「嚴格版」,適合契約驗證。
| 實作類別 | 特性 | 適用場景 |
|---|---|---|
| LinkedList | 同時實作 List 與 Queue,雙向鏈表 |
單執行緒或外部同步環境 |
| PriorityQueue | 堆積排序,自然順序或 Comparator 定序,非執行緒安全 |
單執行緒優先級任務排程 |
| ConcurrentLinkedQueue | 無鎖 (CAS) 鏈表,**高併發無阻塞**,弱一致性迭代器 | 高吞吐生產者-消費者、事件總線 |
size() 需遍歷計算,**極慢**,避免頻繁呼叫ConcurrentModificationExceptionBlockingQueue 擴充 Queue,新增阻塞操作:
put(E e):滿時阻塞等待take():空時阻塞等待offer(e, timeout, unit)、poll(timeout, unit):超時控制
class Producer implements Runnable {
private final BlockingQueue<Task> queue;
Producer(BlockingQueue<Task> q) { queue = q; }
public void run() {
try { while (true) queue.put(produceTask()); }
catch (InterruptedException ex) { Thread.currentThread().interrupt(); }
}
Task produceTask() { /* ... */ }
}
class Consumer implements Runnable {
private final BlockingQueue<Task> queue;
Consumer(BlockingQueue<Task> q) { queue = q; }
public void run() {
try { while (true) process(queue.take()); }
catch (InterruptedException ex) { Thread.currentThread().interrupt(); }
}
void process(Task t) { /* ... */ }
}
// 啟動
BlockingQueue<Task> q = new LinkedBlockingQueue<>(100); // 有界
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
new Thread(new Consumer(q)).start();
| 實作 | 底層結構 | 界限 | 特性 | 典型用途 |
|---|---|---|---|---|
| ArrayBlockingQueue | 環狀陣列 | 有界 (固定) | 公平/非公平鎖可選 | 固定緩衝區、高效能 |
| LinkedBlockingQueue | 鏈表節點 | 可選有界 (預設 Integer.MAX_VALUE) | 幾乎無 put 阻塞 | 通用生產者-消費者 |
| PriorityBlockingQueue | 優先級堆 | 無界 | 元素需 Comparable 或提供 Comparator |
優先級任務排程、替代 TreeSet |
| DelayQueue | 優先級堆 | 無界 | 元素實作 Delayed,到期才能取出 |
定時任務、快取過期清理 |
| SynchronousQueue | 無容量 (直接交接) | 0 | 生產者等消費者,極低延遲交接 | 線程池 Executors.newCachedThreadPool() 內部使用 |
class NanoTask implements Delayed {
private final long triggerNanos;
private final Runnable action;
NanoTask(long delayNanos, Runnable action) {
this.triggerNanos = System.nanoTime() + delayNanos;
this.action = action;
}
public long getDelay(TimeUnit unit) {
return unit.convert(triggerNanos - System.nanoTime(), TimeUnit.NANOSECONDS);
}
public int compareTo(Delayed o) {
return Long.compare(this.triggerNanos, ((NanoTask)o).triggerNanos);
}
public void execute() { action.run(); }
}
// 使用
DelayQueue<NanoTask> timer = new DelayQueue<>();
timer.put(new NanoTask(TimeUnit.SECONDS.toNanos(5), () -> System.out.println("5秒後執行")));
// 執行緒輪詢
new Thread(() -> {
while (true) {
try { timer.take().execute(); }
catch (InterruptedException e) { break; }
}
}).start();
ConcurrentHashMap 實作 ConcurrentMap,提供兩大原子複合操作:
// 原子化: 僅當 key 不存在時放入
V old = map.putIfAbsent(key, newValue);
if (old != null) { /* key 已存在,old 為舊值 */ }
// 等價同步代碼 (效能差、易錯)
synchronized(map) {
if (!map.containsKey(key)) return map.put(key, value);
else return map.get(key);
}
// 原子化: 僅當 key 映射到指定 value 時移除
boolean removed = map.remove(key, expectedValue);
// 等價同步代碼
synchronized(map) {
if (map.get(key).equals(value)) {
map.remove(key); return true;
}
return false;
}
volatile 節點 + 不變節點模式)Collections.synchronizedMap 或 HashtableCopyOnWriteArrayList、CopyOnWriteArraySet 採用寫時複製策略:
add/remove/set) 複製底層陣列、修改副本、原子替換引用get/iterator/for-each) 直接存取當前陣列,**完全無同步開銷**ConcurrentModificationException**:遍歷快照,後續操作見新版本| 優勢 | 代價 | 最佳適用 |
|---|---|---|
| 讀取極快、無鎖 | 寫入複製陣列 O(n) | 事件監聽器清單 (Swing 仍用 EventListenerList) |
| 迭代器絕對安全 | 記憶體雙倍 (瞬間) | 配置資料、白名單/黑名單、服務註冊表 |
| 無需鎖管理 | 寫入後讀取舊資料 (最終一致性) | 發布-訂閱、觀察者模式主體 |
List<String> cow = new CopyOnWriteArrayList<>(Arrays.asList("A", "B"));
List<String> normal = new ArrayList<>(Arrays.asList("A", "B"));
Iterator<String> itCow = cow.iterator();
Iterator<String> itNormal = normal.iterator();
cow.add("C"); normal.add("C"); // 迭代器建立後修改
// cow 迭代器正常完成
while (itCow.hasNext()) System.out.print(itCow.next() + " "); // A B
// normal 迭代器拋 ConcurrentModificationException
try { while (itNormal.hasNext()) System.out.print(itNormal.next() + " "); }
catch (ConcurrentModificationException e) { System.out.println("CME 拋出!"); }
LinkedBlockingQueue (無界) / ArrayBlockingQueue (有界、低延遲)PriorityBlockingQueueDelayQueueConcurrentHashMap (首選),利用 putIfAbsent/remove(key,val) 原子操作CopyOnWriteArrayList/SetPriorityQueue、ArrayDeque (雙端佇列)Java 5 並發集合框架解決了傳統 synchronized 集合的效能瓶頸與 ConcurrentModificationException 痛點。掌握各實作特性與適用邊界,是構建高併發 Java 系統的必修課。