一、Java 隊列體系概覽
Q1:Java 中 Queue 相關的接口和類有哪些?它們的關係是什麼?
- 核心接口:
Queue<E>:基礎 FIFO 隊列(offer/add,poll/remove,peek/element)Deque<E>:雙端隊列(支持頭尾插入/刪除),繼承QueueBlockingQueue<E>:阻塞隊列(線程安全),繼承QueueTransferQueue<E>:可傳遞元素的阻塞隊列(如LinkedTransferQueue)
- 常用實現類分類:
|
類型 |
非阻塞(普通隊列) |
阻塞隊列(線程安全) |
|
基於鏈表 |
|
|
|
基於數組 |
|
|
|
無存儲結構 |
— |
|
|
優先級隊列 |
|
|
注意:
LinkedList實現了Deque,但不是線程安全的ArrayDeque比LinkedList更高效(緩存友好、無節點對象開銷)
二、普通隊列 vs 阻塞隊列
Q2:add/offer、remove/poll、element/peek 有何區別?
|
方法 |
拋異常 |
返回特殊值 |
阻塞 |
超時 |
|
插入 |
|
|
|
|
|
移除 |
|
|
|
|
|
查看 |
|
|
— |
— |
- 關鍵區別:
add()在容量滿時拋IllegalStateExceptionoffer()在容量滿時返回false(適用於有界隊列)- 阻塞隊列 的
put/take會在隊列滿/空時永久阻塞,直到條件滿足
最佳實踐:
在不確定隊列狀態時,優先使用offer()/poll()避免異常。
三、ArrayBlockingQueue vs LinkedBlockingQueue
Q3:ArrayBlockingQueue 和 LinkedBlockingQueue 有什麼區別?如何選型?
|
特性 |
ArrayBlockingQueue |
LinkedBlockingQueue |
|
底層結構 |
有界數組(必須指定容量) |
無界鏈表(默認 |
|
鎖機制 |
一把鎖( |
兩把鎖( |
|
內存佔用 |
固定(預分配) |
動態增長(Node 對象開銷) |
|
性能 |
小容量時快(緩存友好) |
高併發吞吐更高(鎖分離) |
|
風險 |
安全(有界防 OOM) |
默認無界 → 可能 OOM! |
- 線程池為何常用 LinkedBlockingQueue?
因為其高吞吐特性適合任務緩衝,但生產環境務必設置合理容量!
避坑指南:
// 危險!可能 OOM new LinkedBlockingQueue<>(); // 安全做法 new LinkedBlockingQueue<>(1000);
四、SynchronousQueue:零容量隊列
Q4:SynchronousQueue 是什麼?它有什麼特殊用途?
- 核心特性:
- 容量為 0,不存儲元素
put()必須等待另一個線程take(),反之亦然- 本質是線程間直接移交(handoff)
- 應用場景:
- 線程池的“直接提交”策略:
Executors.newCachedThreadPool()使用SynchronousQueue - 高吞吐、低延遲的生產者-消費者模型(無緩衝,即時傳遞)
- 公平模式:
new SynchronousQueue(true):FIFO 順序移交false(默認):棧式 LIFO,性能略高
優勢: 避免任務堆積,快速反饋系統壓力(配合拒絕策略)。