`BlockingQueue` 是 `Queue` 子介面,新增**阻塞插入 (`put`)** 與**阻塞移除 (`take`)** 語義:
| 操作 | 拋出異常 | 返回布爾/值 | 阻塞等待 | 超時等待 |
|---|---|---|---|---|
| 插入 | `add(e)` → `IllegalStateException` | `offer(e)` → `true/false` | `put(e)` | `offer(e, timeout, unit)` |
| 移除 | `remove()` → `NoSuchElementException` | `poll()` → `element/null` | `take()` | `poll(timeout, unit)` |
| 檢查 | `element()` → `NoSuchElementException` | `peek()` → `element/null` | 不可用 | 不可用 |
// ArrayBlockingQueue.put 簡化
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); // 可中斷獲取鎖
try {
while (count == items.length) // 條件不滿足
notFull.await(); // 釋放鎖,進入 WAITING (parking)
insert(e); // 入隊
notEmpty.signal(); // 喚醒一個消費者
} finally { lock.unlock(); }
}
// Condition.await() 內部
public final void await() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
Node node = addConditionWaiter(); // 加入條件等待隊列
int savedState = fullyRelease(node); // 釋放鎖
try {
while (!isOnSyncQueue(node)) // 等待被 signal 移入同步隊列
LockSupport.park(this); // 核心:掛起當前線程
} finally {
// 重新獲取鎖...
}
}
RUNNABLE
│ lock.lockInterruptibly() 獲取鎖失敗
▼
BLOCKED (等待監視器鎖)
│
│ lock.lock() 成功 → RUNNABLE
│
│ Condition.await() / LockSupport.park()
▼
WAITING / TIMED_WAITING (parking)
│
│ Condition.signal() / LockSupport.unpark() / 中斷 / 超時
▼
RUNNABLE (重新競爭鎖)
需要固定緩衝、公平性、可預測記憶體?
是 → ArrayBlockingQueue(fair=true/false)
否
需要優先級排序?
是 → PriorityBlockingQueue
否
需要延遲/定時執行?
是 → DelayQueue
否
需要直接移交、零拷貝、高併發短任務?
是 → SynchronousQueue (非公平吞吐最高 / 公平保序)
否
需要雙端操作 / 工作竊取?
是 → LinkedBlockingDeque
否
需要顯式同步移交確認?
是 → LinkedTransferQueue
否
通用高吞吐生產消費 (指定容量防 OOM)?
是 → LinkedBlockingQueue(capacity)
否 → 重新評估架構
| 指標 | 獲取方式 | 告警建議 |
|---|---|---|
| 隊列大小 | `queue.size()` | > 80% 容量持續 5min (有界) / 持續增長 (無界) |
| 剩餘容量 | `queue.remainingCapacity()` | < 20% 容量 |
| 生產者阻塞時間 | 自定義 `offer(timeout)` 統計 / JFR | P99 > 100ms |
| 消費者空閒時間 | `poll(timeout)` 返回 null 頻率 | 長期空閒 → 線程池可縮容 |
`BlockingQueue` 是 Java 併發包的基石,七大實現各有設計權衡。理解「單鎖 vs 雙鎖、有界 vs 無界、FIFO vs 優先級 vs 延遲 vs 直接移交、Condition await/signal → LockSupport.park → OS 原語」完整鏈路,才能在架構選型、效能調優、故障診斷中遊刃有餘。下一篇將實戰《高併發場景下阻塞隊列動態監控、背壓控制與無鎖隊列 (Disruptor/JCTools) 遷移指南》。