Java 阻塞隊列的7種類型小結
更新時間:2025年07月09日 10:16:24 作者:@zcc@
Java中的阻塞隊列是線程安全的隊列結構,包括ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、DelayQueue、SynchronousQueue、LinkedTransferQueue和LinkedBl,下面就來具體介紹一下,感興趣的可以了解一下
在 Java 中,阻塞隊列(BlockingQueue) 是一種線程安全的隊列結構,用于實現(xiàn)生產者-消費者模式。它的核心特性是在隊列為空時阻塞消費者線程,在隊列滿時阻塞生產者線程,從而自動協(xié)調線程之間的協(xié)作。
阻塞隊列的核心特性
- 線程安全:所有操作(如
put
、take
)都是線程安全的。 - 阻塞操作:
- 隊列滿時:生產者線程阻塞(等待消費者消費)。
- 隊列空時:消費者線程阻塞(等待生產者生產)。
- 超時控制:支持帶超時時間的操作(如
offer(timeout, unit)
和poll(timeout, unit)
)。 - 公平策略:部分實現(xiàn)(如
ArrayBlockingQueue
)支持公平鎖,防止線程饑餓。
Java 中的 7 種阻塞隊列
以下是 Java 提供的 7 種阻塞隊列及其特點和適用場景:
1. ArrayBlockingQueue(有界隊列)
- 特點:
- 基于數(shù)組實現(xiàn),容量固定(初始化時指定)。
- 支持公平鎖(默認非公平鎖)。
- 適用場景:
- 需要嚴格限制隊列容量的場景(如任務量可控的線程池)。
- 示例代碼:
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3); queue.put("A"); // 隊列滿時阻塞 String task = queue.take(); // 隊列空時阻塞
2. LinkedBlockingQueue(有界/無界隊列)
- 特點:
- 基于鏈表實現(xiàn),默認容量為
Integer.MAX_VALUE
(可視為無界)。 - 入隊和出隊使用獨立鎖(
putLock
和takeLock
),提高并發(fā)性能。
- 基于鏈表實現(xiàn),默認容量為
- 適用場景:
- 任務量不可預測的高吞吐量場景(如線程池默認隊列)。
- 示例代碼:
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(100); // 指定容量 queue.put(1); // 隊列滿時阻塞 Integer task = queue.take(); // 隊列空時阻塞
3. PriorityBlockingQueue(無界優(yōu)先級隊列)
- 特點:
- 無界隊列,基于優(yōu)先級堆實現(xiàn)。
- 元素必須實現(xiàn)
Comparable
接口或提供比較器。
- 適用場景:
- 需要按優(yōu)先級處理任務(如緊急任務優(yōu)先)。
- 示例代碼:
BlockingQueue<PriorityTask> queue = new PriorityBlockingQueue<>(); queue.put(new PriorityTask(1)); // 任務優(yōu)先級由 compareTo() 決定 PriorityTask task = queue.take();
4. DelayQueue(延遲隊列)
- 特點:
- 無界隊列,元素必須實現(xiàn)
Delayed
接口。 - 只有在延遲時間到達后,任務才能被取出。
- 無界隊列,元素必須實現(xiàn)
- 適用場景:
- 定時任務(如緩存過期、訂單超時)。
- 示例代碼:
DelayQueue<DelayedTask> queue = new DelayQueue<>(); queue.put(new DelayedTask(5000)); // 5 秒后可用 DelayedTask task = queue.take(); // 等待任務延遲時間到期
5. SynchronousQueue(同步隊列)
- 特點:
- 無容量隊列,每個插入操作必須等待一個對應的移除操作。
- 生產者和消費者直接傳遞數(shù)據(jù)。
- 適用場景:
- 高吞吐量的短任務場景(如
newCachedThreadPool
)。
- 高吞吐量的短任務場景(如
- 示例代碼:
BlockingQueue<String> queue = new SynchronousQueue<>(); queue.put("X"); // 阻塞直到有消費者調用 take() String task = queue.take(); // 阻塞直到有生產者調用 put()
6. LinkedTransferQueue(無界隊列)
- 特點:
- 支持“預占模式”(生產者和消費者直接交互)。
- 高性能的無界隊列。
- 適用場景:
- 需要高效傳遞任務的場景(如快速響應的系統(tǒng))。
- 示例代碼:
BlockingQueue<Integer> queue = new LinkedTransferQueue<>(); queue.put(100); // 直接傳遞給消費者 Integer task = queue.take(); // 立即獲取任務
7. LinkedBlockingDeque(雙向阻塞隊列)
- 特點:
- 雙端隊列,支持從兩端插入/移除元素。
- 可作為有界或無界隊列。
- 適用場景:
- 工作竊取算法(如
ForkJoinPool
)。
- 工作竊取算法(如
- 示例代碼:
BlockingQueue<String> queue = new LinkedBlockingDeque<>(100); queue.put("A"); // 從尾部插入 String task = queue.take(); // 從頭部移除
阻塞隊列的核心方法
方法 | 行為 | 拋出異常 | 返回布爾值 | 阻塞 | 超時阻塞 |
---|---|---|---|---|---|
add(E e) | 插入元素 | 隊列滿時拋異常 | - | 否 | 否 |
offer(E e) | 插入元素 | 隊列滿時返回 false | - | 否 | 否 |
offer(E e, long timeout, TimeUnit unit) | 插入元素 | 超時后返回 false | - | 是 | 是 |
put(E e) | 插入元素 | - | - | 是 | 否 |
remove() | 移除元素 | 隊列空時拋異常 | - | 否 | 否 |
poll() | 移除元素 | 隊列空時返回 null | - | 否 | 否 |
poll(long timeout, TimeUnit unit) | 移除元素 | 超時后返回 null | - | 是 | 是 |
take() | 移除元素 | - | - | 是 | 否 |
如何選擇阻塞隊列?
- 有界 vs 無界:
- 有界隊列(如 ArrayBlockingQueue):防止內存溢出,需合理設置容量。
- 無界隊列(如 LinkedBlockingQueue):可能導致任務堆積,需結合拒絕策略使用。
- 優(yōu)先級需求:
- 使用 PriorityBlockingQueue 實現(xiàn)優(yōu)先級排序。
- 延遲任務:
- 使用 DelayQueue 實現(xiàn)定時或延遲執(zhí)行。
- 高性能場景:
- SynchronousQueue 適合高吞吐量的短任務。
- LinkedTransferQueue 適合快速傳遞任務的場景。
示例:使用阻塞隊列實現(xiàn)生產者-消費者模型
import java.util.concurrent.*; public class ProducerConsumerExample { public static void main(String[] args) { BlockingQueue<String> queue = new LinkedBlockingQueue<>(10); // 生產者線程 Thread producer = new Thread(() -> { try { for (int i = 0; i < 10; i++) { String task = "Task-" + i; queue.put(task); // 隊列滿時阻塞 System.out.println("Produced: " + task); Thread.sleep(100); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); // 消費者線程 Thread consumer = new Thread(() -> { try { while (true) { String task = queue.take(); // 隊列空時阻塞 System.out.println("Consumed: " + task); Thread.sleep(200); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); producer.start(); consumer.start(); } }
注意事項
- 避免內存泄漏:
- 使用無界隊列時,需結合線程池的拒絕策略(如
CallerRunsPolicy
)。
- 使用無界隊列時,需結合線程池的拒絕策略(如
- 公平性:
ArrayBlockingQueue
支持公平鎖(構造函數(shù)傳入true
)。
- 線程中斷:
- 阻塞操作(如
put
/take
)會響應中斷,需捕獲InterruptedException
。
- 阻塞操作(如
通過合理選擇阻塞隊列類型,可以高效地實現(xiàn)線程間的協(xié)作,解決生產者-消費者問題。
到此這篇關于Java 阻塞隊列的7種類型小結的文章就介紹到這了,更多相關Java 阻塞隊列內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
多模塊的springboot項目發(fā)布指定模塊的腳本方式
該文章主要介紹了如何在多模塊的SpringBoot項目中發(fā)布指定模塊的腳本,作者原先的腳本會清理并編譯所有模塊,導致發(fā)布時間過長,通過簡化腳本,只使用`mvn clean install`命令,可以快速發(fā)布指定模塊及其依賴的模塊2025-01-01Resilience4J通過yml設置circuitBreaker的方法
Resilience4j是一個輕量級、易于使用的容錯庫,其靈感來自Netflix Hystrix,但專為Java 8和函數(shù)式編程設計,這篇文章主要介紹了Resilience4J通過yml設置circuitBreaker的方法,需要的朋友可以參考下2022-10-10