阻塞隊列(BlockingQueue)
阻塞隊列(BlockingQueue)

- 阻塞隊列都實現了:BlockingQueue
- JDK提供的七個阻塞隊列

一、特點
1、JDK提供的七個阻塞隊列簡介
①. ArrayBlockingQueue
有界 阻塞隊列——必須指定大小——數組
②. LinkedBlockingQueue
有界 阻塞隊列——默認大小:Integer.MAX_VALUE最大值——鏈表
③. LinkedTransferQueue
無界 阻塞隊列——鏈表
④. PriorityBlockingQueue
無界 阻塞隊列——支持優先級排序
⑤. DelayQueue
無界 阻塞隊列——使用優先級隊列實現的
⑥. SynchronousQueue
不存儲元素 的阻塞隊列
⑦. LinkedBlockingDeque
雙端 阻塞隊列——鏈表
2、其他特點
- 阻塞隊列默認情況下是FIFO(先進先出),PriorityBlockingQueue可以設置優先級出隊列
- BlockingQueue 不接受 null 元素。試圖 add、put 或 offer 一個 null 元素時,某些實現會拋出 NullPointerException。null 被用作指示 poll 操作失敗的警戒值。
- BlockingQueue 實現是線程安全的
二、阻塞隊列的方法
- e 表示插入到隊列的元素
- 其他特殊的方法,見參考。
- 常用方法
阻塞隊列的核心方法有以下幾組
1.拋異常組:add(),remove(),element();
2.返回布爾值組:offer(),poll(),peek();
3.阻塞組:put(),take();
4.超時組:offer(),poll();
1、插入元素
| 描述 | 拋出異常 | 一直阻塞 | 返回特殊的值 | 超時退出 |
|---|---|---|---|---|
| 插入數據 | add(e) | put(e) | offer(e) 推薦 |
offer(e, time, unit) 推薦 |
| 插入成功 | 返回true | 無返回值 | 返回true | 返回true |
| 插入失敗 (隊列滿) |
拋異常 | 一直阻塞,直到插入元素 | 返回false | 等10秒(假如設置的10s) 然后放棄插入,返回false 可用于控制添加元素的速度 |
2、獲取元素——并移除隊列的頭元素
| 描述 | 拋出異常 | 一直阻塞 | 返回特殊的值 | 超時退出 |
|---|---|---|---|---|
| 獲取元素 | remove() | take() | poll() | poll(time, unit) |
| 獲取成功 | 返回元素 | 返回元素 | 返回元素 | 返回元素 |
| 獲取失敗 (隊列空) |
拋異常 | 一直阻塞,直到獲取到元素 | 返回null | 等10秒(假如設置的10s) 然后null 可用于控制消費的速度 |
3、獲取元素——不移除隊列的元素
| 描述 | 拋出異常 | 返回特殊的值 |
|---|---|---|
| 獲取元素 | element() | peek() |
| 獲取成功 | 返回元素 | 返回元素 |
| 獲取失敗 (隊列空) |
拋異常 | 返回null |
4、推薦使用
- 一般情況下 offer() 和 poll() 方法配合使用
程序中常用的是 offer() 和 poll() 方法,因為這兩個方法比較友好,不會報錯。
- put() 和 take() 阻塞方法配合使用
- add() 和 remove() 方法會配合使用
5、測試
- 自己去測
package com.cc.testproject.utils;
import java.time.LocalDateTime;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
/**
* <p>存放隊列</p>
*
* @author --
* @since 2024/1/9
*/
public class Task01 {
//有界阻塞隊列——FIFO(先進先出)——必須指定大小——數組
private static final ArrayBlockingQueue<String> QUEUE1 = new ArrayBlockingQueue<>(1);
//有界阻塞隊列——FIFO(先進先出)——默認大小:int最大值——鏈表
private static final LinkedBlockingQueue <String> QUEUE2 = new LinkedBlockingQueue<>();
//無界阻塞隊列——FIFO(先進先出)——無限大——鏈表
private static final LinkedTransferQueue <String> QUEUE3 = new LinkedTransferQueue<>();
public static void main(String[] args) throws InterruptedException {
boolean offer = QUEUE1.offer("1");
System.out.println("第1次添加:" + offer + "-時間:" + LocalDateTime.now());
boolean offer1 = QUEUE1.offer("2");
System.out.println("第2次添加:" + offer1 + "-時間:" + LocalDateTime.now());
System.out.println(QUEUE1.take());
// System.out.println(QUEUE1.element());
System.out.println(QUEUE1.peek());
System.out.println(QUEUE1);
// System.out.println(QUEUE1.poll(5, TimeUnit.SECONDS));
// System.out.println(QUEUE1.poll());
// System.out.println(QUEUE1.remove());
// System.out.println(QUEUE1.take());
// System.out.println(QUEUE1.remove());
// System.out.println(QUEUE1.remove());
// System.out.println(QUEUE1.take());
// System.out.println(QUEUE1.take());
// System.out.println(QUEUE1.poll());
// System.out.println(QUEUE1.poll(5, TimeUnit.SECONDS));
//如隊列滿:等10秒,然后放棄插入,返回false
// boolean offer = QUEUE1.offer("1", 10, TimeUnit.SECONDS);
// System.out.println("第1次添加:" + offer + "-時間:" + LocalDateTime.now());
// boolean offer1 = QUEUE1.offer("2", 10, TimeUnit.SECONDS);
// System.out.println("第2次添加:" + offer1 + "-時間:" + LocalDateTime.now());
//
// System.out.println("添加完成:" + QUEUE1);
// 如隊列滿:拋異常
// boolean add1 = QUEUE1.add("1");
// System.out.println("第1次添加:" + add1);
// boolean add2 = QUEUE1.add("2");
// System.out.println("第2次添加:" + add2);
//如隊列滿:一直等
// QUEUE1.put("1");
// System.out.println("第1次添加:" + LocalDateTime.now());
// QUEUE1.put("2");
// System.out.println("第2次添加:" + LocalDateTime.now());
}
}
三、使用場景、個人理解
1、使用場景
-
需要順序執行,且是耗時操作,可用來裝用戶的請求
-
阻塞隊列在多線程編程中有許多使用場景,包括但不限于:
- 生產者-消費者模式:用于在生產者和消費者之間進行線程安全的數據交換。
- 任務調度:用于實現線程池中的任務隊列,控制任務的提交和執行。
- 數據傳輸:用于在不同線程之間傳遞數據,例如在生產者和消費者之間傳遞數據。
- 事件驅動編程:用于在事件處理中進行線程間通信和協調。
- 限流和流量控制:用于控制系統的并發訪問量,防止系統過載。

2、個人理解
- 阻塞隊列之所以叫阻塞隊列,是因為它可以在添加或者獲取元素的時候阻塞添加或獲取的線程。直到線程達到自己的目的。
- 阻塞隊列之所以被稱為阻塞隊列,是因為當隊列已滿時,嘗試向隊列中添加元素的線程會被阻塞,直到隊列有空間為止;當隊列為空時,嘗試從隊列中獲取元素的線程會被阻塞,直到隊列中有元素為止。這種行為可以確保線程安全地在隊列中添加或獲取元素。
四、參考:

- 對雙端隊列,其他隊列感興趣的,可以見下面:
1、http://t.csdnimg.cn/BAAcc 或 這里
2、http://t.csdnimg.cn/sGtuA 或 這里
3、http://t.csdnimg.cn/fA8T7 或 這里
4、https://blog.51cto.com/u_16099200/7290591
浙公網安備 33010602011771號