阻塞队列(BlockingQueue)
1.阻塞队列(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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)