问:JAVA阻塞队列实现类及最佳实践?
在多线程编程中,阻塞队列作为一种关键的数据结构,为线程间安全、高效的数据交换提供了重要支持。Java的java.util.concurrent
包中提供了多种阻塞队列的实现,每种实现都有其独特的特点和适用场景。
一、阻塞队列实现类
以下是Java中BlockingQueue
接口的主要实现类及差异。
实现类 | 队列结构 | 容量特性 | 公平性支持 | 元素特性 | 特殊功能 |
---|---|---|---|---|---|
ArrayBlockingQueue | 数组 | 有界,创建时指定且不可变 | 支持 | 无特殊要求 | 无 |
LinkedBlockingQueue | 链表 | 可选有界,动态调整容量 | 不支持 | 无特殊要求 | 无 |
PriorityBlockingQueue | 无界 | 无界 | 不支持 | 必须实现Comparable 或提供Comparator | 优先级排序 |
DelayQueue | 无界 | 无界 | 不支持 | 必须实现Delayed 接口 | 延时获取元素 |
SynchronousQueue | 不存储元素 | 无容量概念 | 支持 | 无特殊要求 | 插入与获取操作必须配对 |
LinkedTransferQueue | 链表 | 无界 | 不支持 | 无特殊要求 | 直接传输元素给消费者 |
ConcurrentLinkedQueue (非BlockingQueue ) | 链表 | 无界 | 不适用 | 无特殊要求 | 非阻塞,高效并发操作 |
1. 队列结构
ArrayBlockingQueue
:采用数组结构,是唯一的数组结构实现。数组结构在访问速度上通常较快,但在插入和删除元素时,可能需要移动大量数据。LinkedBlockingQueue
、PriorityBlockingQueue
、DelayQueue
、LinkedTransferQueue
:均采用链表结构。链表结构在插入和删除元素时,通常只需要修改指针,因此效率较高。ConcurrentLinkedQueue
:虽然也是链表结构,但它不是BlockingQueue
接口的实现,而是提供了非阻塞的并发操作。
2. 容量特性
ArrayBlockingQueue
:容量在创建时指定且不可变,因此在使用过程中需要合理设置容量大小。LinkedBlockingQueue
:容量可以动态调整,通过指定Integer.MAX_VALUE
可以创建无界队列。这使得它在处理不确定数量的任务时更加灵活。PriorityBlockingQueue
、DelayQueue
:均为无界队列,没有容量限制。这可能会导致在内存紧张的情况下出现内存溢出的问题。SynchronousQueue
:不存储元素,因此没有容量概念。它要求插入与获取操作必须配对,否则线程会阻塞。ConcurrentLinkedQueue
:也是无界的,但它是非阻塞的,因此不会出现阻塞等待的情况。
3. 公平性支持
ArrayBlockingQueue
、SynchronousQueue
:支持公平的访问队列。这意味着线程可以按照它们加入队列的顺序来访问队列中的元素,从而避免了“饥饿”现象。- 其他实现类均不支持公平的访问队列,这可能会导致某些线程长时间得不到执行的机会。
4. 元素特性
PriorityBlockingQueue
:元素必须实现Comparable
接口或提供Comparator
比较器,以便在队列中进行优先级排序。这使得它适用于需要按照优先级处理任务的场景。DelayQueue
:元素必须实现Delayed
接口,该接口定义了元素何时可以被获取。这使得它适用于需要延时获取元素的场景,如定时任务。- 其他实现类对元素没有特殊要求,可以存储任意类型的对象。
5. 特殊功能
PriorityBlockingQueue
:支持优先级排序,可以按照元素的优先级顺序获取元素。DelayQueue
:支持延时获取元素,可以在指定的时间后获取元素。SynchronousQueue
:要求插入与获取操作必须配对,否则线程会阻塞。这使得它适用于需要严格同步的场景。LinkedTransferQueue
:支持直接传输元素给消费者,而无需先将元素存储在队列中。这使得它在某些场景下可以提高效率。ConcurrentLinkedQueue
:提供高效的非阻塞并发操作,适用于高并发场景下的队列操作。但它不支持阻塞和超时机制。
二、阻塞队列的最佳实践
阻塞队列在多线程编程中扮演着重要角色,特别是在生产者-消费者模式中。
1. 选择合适的阻塞队列实现
在选择阻塞队列实现时,应根据具体的应用场景和需求来选择合适的实现类。例如,如果需要按照优先级处理任务,可以选择PriorityBlockingQueue
;如果需要延时获取元素,可以选择DelayQueue
;如果需要严格的同步和配对操作,可以选择SynchronousQueue
;如果需要高效的非阻塞并发操作,可以选择ConcurrentLinkedQueue
(但需要注意它不支持阻塞和超时机制)。
示例:
// 创建一个固定大小的阻塞队列
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
2. 使用正确的插入和移除方法
阻塞队列提供了put()
和take()
方法,它们会分别阻塞当前线程直到可以插入元素或移除元素。对于非阻塞操作,可以使用offer()
和poll()
方法。在使用这些方法时,需要注意它们的返回值和异常处理。
示例:
// 生产者线程向队列中插入元素
public void producer() throws InterruptedException {queue.put(1); // 如果队列满,则阻塞直到可以插入
}// 消费者线程从队列中移除元素
public void consumer() throws InterruptedException {Integer item = queue.take(); // 如果队列空,则阻塞直到可以移除// 处理元素
}
3. 处理中断
在使用阻塞队列时,应该考虑到线程可能被中断的情况。put()
和take()
方法都会抛出InterruptedException
,需要适当处理这个异常,通常的做法是恢复中断状态。
示例:
// 处理中断的消费者线程
public void consumerWithInterrupt() {try {while (true) {Integer item = queue.take();// 处理元素}} catch (InterruptedException e) {Thread.currentThread().interrupt(); // 恢复中断状态// 处理中断后的逻辑}
}
4. 避免忙等待
在使用非阻塞方法(如offer()
和poll()
)时,应该避免忙等待的情况。可以通过适当的等待策略(如Thread.sleep()
、Object.wait()
等)来避免忙等待带来的资源浪费。
示例:
// 避免忙等待的消费者线程
public void consumerWithoutBusyWaiting() {while (true) {Integer item = queue.poll();if (item != null) {// 处理元素} else {try {Thread.sleep(100); // 等待一段时间后再尝试} catch (InterruptedException e) {Thread.currentThread().interrupt(); // 恢复中断状态}}}
}
5. 合理设置队列容量
阻塞队列的容量应该根据具体的应用场景来合理设置。过小的容量可能导致频繁的阻塞和唤醒,影响性能;过大的容量则可能占用过多的内存资源,甚至导致内存溢出。因此,在设置队列容量时,需要综合考虑任务的处理速度、内存使用情况以及系统的稳定性等因素。
代码示例:
// 创建一个具有合理容量的阻塞队列(这里以100为例)
BlockingQueue<Integer> queueWithCapacity = new LinkedBlockingQueue<>(100);
6. 使用多个队列实现优先级处理
在某些应用中,可能需要处理不同优先级的任务。这时可以使用多个阻塞队列来实现优先级处理。例如,可以创建两个不同优先级的阻塞队列,一个用于存储高优先级任务,另一个用于存储低优先级任务。消费者线程可以先尝试从高优先级队列中获取任务,如果高优先级队列为空,则再从低优先级队列中获取任务。
示例:
// 创建两个不同优先级的阻塞队列
BlockingQueue<Integer> highPriorityQueue = new PriorityBlockingQueue<>();
BlockingQueue<Integer> lowPriorityQueue = new LinkedBlockingQueue<>();// 生产者线程向不同优先级的队列中插入元素
public void producerWithPriority() throws InterruptedException {highPriorityQueue.put(1); // 高优先级任务lowPriorityQueue.put(2); // 低优先级任务
}// 消费者线程优先处理高优先级队列中的任务
public void consumerWithPriority() throws InterruptedException {while (true) {Integer highPriorityItem = highPriorityQueue.poll();if (highPriorityItem != null) {// 处理高优先级任务} else {Integer lowPriorityItem = lowPriorityQueue.take(); // 如果高优先级队列为空,则处理低优先级任务// 处理低优先级任务// ...}}
}
7. 使用超时机制
阻塞队列还提供了带有超时参数的方法,如offer(E e, long timeout, TimeUnit unit)
和poll(long timeout, TimeUnit unit)
。这些方法允许线程在指定的时间内尝试插入或移除元素,如果超时则返回失败,而不会一直阻塞。这对于需要限时完成的任务处理非常有用。
示例:
// 尝试在指定时间内向队列中插入元素
public boolean tryOfferWithTimeout(BlockingQueue<Integer> queue, Integer item, long timeout, TimeUnit unit) throws InterruptedException {return queue.offer(item, timeout, unit);
}// 尝试在指定时间内从队列中移除元素
public Integer tryPollWithTimeout(BlockingQueue<Integer> queue, long timeout, TimeUnit unit) throws InterruptedException {return queue.poll(timeout, unit);
}
8. 监控和调优
在实际应用中,应该监控阻塞队列的使用情况,包括队列的长度、等待线程的数量、元素的插入和移除速度等。这些信息可以帮助你了解系统的运行状态,并及时进行调优。例如,如果发现队列长度经常达到上限,可能需要增加队列容量或优化任务处理速度。
9. 考虑异常处理策略
在使用阻塞队列时,还需要考虑异常处理策略。除了处理InterruptedException
外,还应该考虑其他可能的异常,如NullPointerException
(当尝试插入null
元素时)和IllegalStateException
(当使用不支持的操作时)。根据具体的应用场景,可以选择合适的异常处理策略,如记录日志、重试操作或终止线程等。
10. 结合其他并发工具使用
阻塞队列通常与其他并发工具结合使用,如线程池(ThreadPoolExecutor
)、信号量(Semaphore
)和倒计时锁存器(CountDownLatch
)等。这些工具可以帮助你更好地管理线程和协调任务执行。例如,你可以使用线程池来提交任务到阻塞队列中,并使用信号量来控制同时执行的任务数量。
三、结语
阻塞队列是多线程编程中非常重要的数据结构,它提供了线程安全的队列操作。在选择和使用阻塞队列时,需要根据具体的应用场景和需求来选择合适的实现类和配置参数。同时,还需要注意处理中断、避免忙等待、合理设置队列容量、使用多个队列实现优先级处理以及使用超时机制等最佳实践。通过结合其他并发工具使用,并考虑异常处理策略和监控调优,可以构建高效稳定的多线程应用。
相关文章:
问:JAVA阻塞队列实现类及最佳实践?
在多线程编程中,阻塞队列作为一种关键的数据结构,为线程间安全、高效的数据交换提供了重要支持。Java的java.util.concurrent包中提供了多种阻塞队列的实现,每种实现都有其独特的特点和适用场景。 一、阻塞队列实现类 以下是Java中Blocking…...

Springboot3 + MyBatis-Plus + MySql + Vue + ProTable + TS 实现后台管理商品分类(最新教程附源码)
Springboot3 MyBatis-Plus MySql Uniapp 商品加入购物车功能实现(针对上一篇sku) 1、效果展示2、数据库设计3、后端源码3.1 application.yml 方便 AliOssUtil.java 读取3.2 model 层3.2.1 BaseEntity3.2.1 GoodsType3.2.3 GoodsTypeSonVo3.3 Controll…...

消费电子制造企业如何使用SAP系统提升运营效率与竞争力
在当今这个日新月异的消费电子市场中,企业面临着快速变化的需求、激烈的竞争以及不断攀升的成本压力。为了在这场竞赛中脱颖而出,消费电子制造企业纷纷寻求数字化转型的突破点,其中,SAP系统作为业界领先的企业资源规划(ERP)解决方…...

算法记录——树
二叉树 3.1二叉树的最大深度 思路:二叉树的最大深度 根节点的最大高度。因此本题可以转换为求二叉树的最大高度。 而求高度的时候应该采用后序遍历。遍历顺序为:左右中。每次遍历的节点按后序遍历顺序,先收集左右孩子的最大高度,…...
单片机在控制和自动化任务中的应用场景广泛
单片机在控制和自动化任务中的应用场景广泛,以下是一些具体示例: 1. 家电控制 洗衣机:单片机用于控制洗衣周期、温度和水位。微波炉:控制加热时间、功率和用户界面。 2. 工业自动化 生产线监控:单片机用于控制传送…...

UEFI EDK2框架学习(三)——protocol
一、Protocol协议 搜索支持特定Protocol的设备,获取其Handle gBS->LocateHandleBuffer 将内存中的Driver绑定到给定的ControllerHandle gBS->OpenProtocol 二、代码实现 Protocol.c #include <Uefi.h> #include <Library/UefiLib.h> #includ…...

PostgreSQL的字段存储类型了解
PostgreSQL的字段存储类型了解 在 PostgreSQL 中,每个字段(列)都有其存储类型,这些存储类型决定了数据库如何存储和处理该字段的数据。了解和适当地利用这些存储类型,可以提高数据库的性能和存储效率。 主要的存储类…...

CTFshow 命令执行 web29~web36(正则匹配绕过)
目录 web29 方法一:include伪协议包含文件读取 方法二:写入文件 方法三:通识符 web30 方法一:filter伪协议文件包含读取 方法二:命令执行函数绕过 方法三:写入文件 web31 方法一:filter伪…...

【顺序表使用练习】发牌游戏
【顺序表使用练习】发牌游戏 1. 介绍游戏2. 实现52张牌3. 实现洗牌4. 实现发牌5. 效果展示 1. 介绍游戏 首先先为大家介绍一下设计要求 实现52张牌(这里排除大小王)洗牌——打乱牌的顺序发牌——3个人,1人5张牌 2. 实现52张牌 创建Code对象创…...

1.7 编码与调制
欢迎大家订阅【计算机网络】学习专栏,开启你的计算机网络学习之旅! 文章目录 前言前言1 基本术语2 常用的编码方法2.1 不归零编码2.2 归零编码2.3 反向归零编码2.4 曼彻斯特编码2.5 差分曼彻斯特编码 3 常用的调制方法3.1 调幅(AM)…...

004集—— txt格式坐标写入cad(CAD—C#二次开发入门)
如图所示原始坐标格式,xy按空格分开,将坐标按顺序在cad中画成多段线: 坐标xy分开并按行重新输入txt,效果如下: 代码如下 : using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Runtime; us…...
CSS中的font-variation-settings:探索字体的可变性
随着Web字体的发展,设计师们不再局限于传统的字体样式。现代Web字体支持可变字体(Variable Fonts),这种字体允许开发者在单一的字体文件中包含多种字形样式。通过使用CSS中的font-variation-settings属性,我们可以控制…...

组合优化与凸优化 学习笔记5 对偶拉格朗日函数
有的时候约束条件有点难搞,我们可以把它放到目标函数里面。 记得之前凸函数的时候的结论吗?一大堆函数,每一段都取最大的,最后会得到一个凸函数。同理,每一段都取最小的,得到的是一个凹函数。就这样&#x…...

监控易监测对象及指标之:Exchange邮件服务器监测
在现代企业运营中,邮件服务器的作用至关重要,它不仅承载着企业内外的信息传递,还是协同工作的重要工具。为了确保邮件服务器的稳定运行,以及邮件的顺畅收发,采用高效的监控系统是不可或缺的。监控易作为一款专业的监控…...

【机器学习基础】Transformer学习
Transformer学习 梯度消失FeedForward层激活函数的主要作用是在网络中加入非线性变换 梯度消失 梯度爆炸 FeedForward层 Transformer结构: Transformer结构主要分为两大部分: 一是Encoder层结构:Encoder 的输入由 Input Embedding 和 Positional Embedding 求和输入Multi…...
mysql如何不使用窗口函数,去统计出入库情况
mysql如何不使用窗口函数,去统计出入库情况 你把这个表看做 进出库表,每个物料把时间正序后 依次累加数量 ,看这个物料的时间线上 是否会出现负数,1号进货5个 2号出库3个 3号你不能出库3个 最多俩个 不然就是负库存,…...

uni-app canvas文本自动换行
封装 支持单行文本超出换行。多行文本顺位排版 // 填充自动换行的文本function fillFeedText({ctx, text, x, y, maxWidth, lineHeight, color, size}) {// 文本配置ctx.setFontSize(size);ctx.setFillStyle(color);// 计算文本换行宽高,换行逻辑const words text…...

【设计模式-职责链】
定义 职责链模式是一种行为设计模式,**它通过将请求发送给链上的多个处理者来避免请求发送者与处理者之间的紧密耦合。每个处理者可以选择处理请求或将其传递给链中的下一个处理者。**这样,可以将处理请求的责任链式组织,从而实现更灵活的请…...
Prompt:在AI时代,提问比答案更有价值
你好,我是三桥君 随着AI技术的飞速发展,我们进入了一个信息爆炸的时代。在这个时代,只要你会提问,AI就能为你提供满意的答案。这种现象让很多人开始思考:在这个答案触手可及的时代,答案的价值是否还像以前…...
whatis命令:关于命令的简短描述
一、命令简介 whatis 命令用于查询命令、函数、文件等的基本用途,查询结果只是一句简短的描述。 例如 $ whatis ls ls (1) - list directory contents返回关于 ls 命令的简短描述。这个结果实质是来自于man手册的一个章节,在较新的L…...

利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...