BlockingQueue 是 Java 并發包中解決生產者-消費者問題的利器。本文系統講解其四大核心實現類、七大核心方法語義差異,並通過完整的生產者-消費者代碼示例,演示阻塞隊列如何優雅實現線程間數據傳輸與背壓控制。
| 實現類 | 底層結構 | 容量 | 排序規則 | 典型場景 |
|---|---|---|---|---|
ArrayBlockingQueue | 數組 | 固定 (構造器指定) | FIFO | 固定緩衝區、高吞吐、公平鎖可選 |
LinkedBlockingQueue | 鏈表 | 可選 (默認 Integer.MAX_VALUE) | FIFO | 無界隊列、吞吐優於 Array、生產快消費慢 |
PriorityBlockingQueue | 堆 (數組) | 無界 | 優先級 (自然序/Comparator) | 任務調度、按優先級處理訂單 |
SynchronousQueue | 無緩衝 (直接移交) | 0 | FIFO (配對) | 線程池拒絕策略、直接移交、高並發傳遞 |
| 方法 | 隊列滿 | 隊列空 | 返回值 | 異常 |
|---|---|---|---|---|
add(e) | 拋出 IllegalStateException | — | boolean | 是 |
offer(e) | 返回 false | — | boolean | 否 |
put(e) | 阻塞等待 | — | void | InterruptedException |
offer(e, timeout) | 超時返回 false | — | boolean | InterruptedException |
poll() | — | 返回 null | E | 否 |
take() | — | 阻塞等待 | E | InterruptedException |
poll(timeout) | — | 超時返回 null | E | InterruptedException |
選型口訣: 生產端首選 put/offer(timeout) 實現背壓;消費端首選 take/poll(timeout) 避免忙等待。
package com.gefufeng;
import java.util.concurrent.BlockingQueue;
public class Producter implements Runnable {
private final BlockingQueue<String> blockingQueue;
public Producter(BlockingQueue<String> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
try {
String msg = "我生產的 " + Thread.currentThread().getName();
blockingQueue.put(msg); // 隊列滿則阻塞
System.out.println(msg);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 重設置中斷標誌
System.out.println("生產中斷");
}
}
}
package com.gefufeng;
import java.util.concurrent.BlockingQueue;
public class Customer implements Runnable {
private final BlockingQueue<String> blockingQueue;
public Customer(BlockingQueue<String> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
String msg = blockingQueue.take(); // 隊列空則阻塞
System.out.println("取出:" + msg);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("消費中斷");
break;
}
}
}
}
package com.gefufeng;
import java.util.concurrent.ArrayBlockingQueue;
public class Executer {
public static void main(String[] args) {
// 容量為 2 的有界隊列,演示阻塞效果
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(2);
Customer consumer = new Customer(queue);
new Thread(consumer, "Consumer").start();
// 每 2 秒啟動一個生產者
while (true) {
try {
Thread.sleep(2000);
new Thread(new Producter(queue), "Producer-" + System.nanoTime()).start();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
}
take() 隊列空 → 阻塞等待。put() 放入數據 → 消費者被喚醒 → 取出打印。take() → 隊列空 → 再次阻塞。put() 阻塞 直到消費者騰出空位 (背壓自動生效)。null 或專用 POISON 實例) 通知消費者退出循環,避免 interrupt() 導致的異常處理分散。drainTo(Collection<? super E> c) 一次性取出所有可用元素,減少鎖競爭,適合批量處理場景。ArrayBlockingQueue 構造器可傳 fair=true 使用公平鎖,避免線程饑餓,但吞吐略降。LinkedBlockingQueue 默認無界,若生產持續快於消費會導致 OOM,生產環境務必指定容量。Executors.newCachedThreadPool() 內部使用 SynchronousQueue,任務直接移交給空閒線程,無隊列緩衝,適合大量短任務。BlockingQueue 以「阻塞」為核心語義,將同步、通訊、數據共享融為一體,是構建高並發管道、任務調度、流控組件的基石。掌握四大實現特性、七大方法語義、生產消費者模式與優雅關閉技巧,即可在實戰中游刃有余地解決線程協作難題。