阻塞隊(duì)列(BlockingQueue)
- 阻塞隊(duì)列都實(shí)現(xiàn)了:BlockingQueue
- JDK提供的七個(gè)阻塞隊(duì)列
一、特點(diǎn)
1、JDK提供的七個(gè)阻塞隊(duì)列簡介
①. ArrayBlockingQueue
有界
阻塞隊(duì)列——必須指定大小——數(shù)組
②. LinkedBlockingQueue
有界
阻塞隊(duì)列——默認(rèn)大?。篒nteger.MAX_VALUE最大值——鏈表
③. LinkedTransferQueue
無界
阻塞隊(duì)列——鏈表
④. PriorityBlockingQueue
無界
阻塞隊(duì)列——支持優(yōu)先級排序
⑤. DelayQueue
無界
阻塞隊(duì)列——使用優(yōu)先級隊(duì)列實(shí)現(xiàn)的
⑥. SynchronousQueue
不存儲元素
的阻塞隊(duì)列
⑦. LinkedBlockingDeque
雙端
阻塞隊(duì)列——鏈表
2、其他特點(diǎn)
- 阻塞隊(duì)列默認(rèn)情況下是FIFO(先進(jìn)先出),PriorityBlockingQueue可以設(shè)置優(yōu)先級出隊(duì)列
- BlockingQueue 不接受 null 元素。試圖 add、put 或 offer 一個(gè) null 元素時(shí),某些實(shí)現(xiàn)會拋出 NullPointerException。null 被用作指示 poll 操作失敗的警戒值。
- BlockingQueue 實(shí)現(xiàn)是線程安全的
二、阻塞隊(duì)列的方法
- e 表示插入到隊(duì)列的元素
- 其他特殊的方法,見參考。
- 常用方法
阻塞隊(duì)列的核心方法有以下幾組
1.拋異常組:add(),remove(),element();
2.返回布爾值組:offer(),poll(),peek();
3.阻塞組:put(),take();
4.超時(shí)組:offer(),poll();
1、插入元素
描述 | 拋出異常 | 一直阻塞 | 返回特殊的值 | 超時(shí)退出 |
---|---|---|---|---|
插入數(shù)據(jù) | add(e) | put(e) |
offer(e) 推薦 |
offer(e, time, unit) 推薦 |
插入成功 | 返回true | 無返回值 | 返回true | 返回true |
插入失敗 (隊(duì)列滿) |
拋異常 | 一直阻塞,直到插入元素 | 返回false | 等10秒(假如設(shè)置的10s) 然后放棄插入,返回false 可用于控制添加元素的速度 |
2、獲取元素——并移除隊(duì)列的頭元素
描述 | 拋出異常 | 一直阻塞 | 返回特殊的值 | 超時(shí)退出 |
---|---|---|---|---|
獲取元素 | remove() | take() | poll() | poll(time, unit) |
獲取成功 | 返回元素 | 返回元素 | 返回元素 | 返回元素 |
獲取失敗 (隊(duì)列空) |
拋異常 | 一直阻塞,直到獲取到元素 | 返回null | 等10秒(假如設(shè)置的10s) 然后null 可用于控制消費(fèi)的速度 |
3、獲取元素——不移除隊(duì)列的元素
描述 | 拋出異常 | 返回特殊的值 |
---|---|---|
獲取元素 | element() | peek() |
獲取成功 | 返回元素 | 返回元素 |
獲取失敗 (隊(duì)列空) |
拋異常 | 返回null |
4、推薦使用
- 一般情況下 offer() 和 poll() 方法配合使用
程序中常用的是 offer() 和 poll() 方法,因?yàn)檫@兩個(gè)方法比較友好,不會報(bào)錯(cuò)。
- 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>存放隊(duì)列</p>
*
* @author --
* @since 2024/1/9
*/
public class Task01 {
//有界阻塞隊(duì)列——FIFO(先進(jìn)先出)——必須指定大小——數(shù)組
private static final ArrayBlockingQueue<String> QUEUE1 = new ArrayBlockingQueue<>(1);
//有界阻塞隊(duì)列——FIFO(先進(jìn)先出)——默認(rèn)大?。篿nt最大值——鏈表
private static final LinkedBlockingQueue <String> QUEUE2 = new LinkedBlockingQueue<>();
//無界阻塞隊(duì)列——FIFO(先進(jìn)先出)——無限大——鏈表
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 + "-時(shí)間:" + LocalDateTime.now());
boolean offer1 = QUEUE1.offer("2");
System.out.println("第2次添加:" + offer1 + "-時(shí)間:" + 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));
//如隊(duì)列滿:等10秒,然后放棄插入,返回false
// boolean offer = QUEUE1.offer("1", 10, TimeUnit.SECONDS);
// System.out.println("第1次添加:" + offer + "-時(shí)間:" + LocalDateTime.now());
// boolean offer1 = QUEUE1.offer("2", 10, TimeUnit.SECONDS);
// System.out.println("第2次添加:" + offer1 + "-時(shí)間:" + LocalDateTime.now());
//
// System.out.println("添加完成:" + QUEUE1);
// 如隊(duì)列滿:拋異常
// boolean add1 = QUEUE1.add("1");
// System.out.println("第1次添加:" + add1);
// boolean add2 = QUEUE1.add("2");
// System.out.println("第2次添加:" + add2);
//如隊(duì)列滿:一直等
// QUEUE1.put("1");
// System.out.println("第1次添加:" + LocalDateTime.now());
// QUEUE1.put("2");
// System.out.println("第2次添加:" + LocalDateTime.now());
}
}
三、使用場景、個(gè)人理解
1、使用場景
-
需要順序執(zhí)行,且是耗時(shí)操作,可用來裝用戶的請求
-
阻塞隊(duì)列在多線程編程中有許多使用場景,包括但不限于:
- 生產(chǎn)者-消費(fèi)者模式:用于在生產(chǎn)者和消費(fèi)者之間進(jìn)行線程安全的數(shù)據(jù)交換。
- 任務(wù)調(diào)度:用于實(shí)現(xiàn)線程池中的任務(wù)隊(duì)列,控制任務(wù)的提交和執(zhí)行。
- 數(shù)據(jù)傳輸:用于在不同線程之間傳遞數(shù)據(jù),例如在生產(chǎn)者和消費(fèi)者之間傳遞數(shù)據(jù)。
- 事件驅(qū)動編程:用于在事件處理中進(jìn)行線程間通信和協(xié)調(diào)。
- 限流和流量控制:用于控制系統(tǒng)的并發(fā)訪問量,防止系統(tǒng)過載。
文章來源:http://www.zghlxwxcb.cn/news/detail-777099.html
2、個(gè)人理解
- 阻塞隊(duì)列之所以叫阻塞隊(duì)列,是因?yàn)樗梢栽谔砑踊蛘攉@取元素的時(shí)候阻塞添加或獲取的線程。直到線程達(dá)到自己的目的。
- 阻塞隊(duì)列之所以被稱為阻塞隊(duì)列,是因?yàn)楫?dāng)隊(duì)列已滿時(shí),嘗試向隊(duì)列中添加元素的線程會被阻塞,直到隊(duì)列有空間為止;當(dāng)隊(duì)列為空時(shí),嘗試從隊(duì)列中獲取元素的線程會被阻塞,直到隊(duì)列中有元素為止。這種行為可以確保線程安全地在隊(duì)列中添加或獲取元素。
四、參考:
文章來源地址http://www.zghlxwxcb.cn/news/detail-777099.html
- 對雙端隊(duì)列,其他隊(duì)列感興趣的,可以見下面:
1、 或 這里
2、 或 這里
3、 或 這里
4、https://blog.51cto.com/u_16099200/7290591
到了這里,關(guān)于阻塞隊(duì)列(BlockingQueue)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!