问: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…...
ICM20948 DMP代码详解(54)
接前一篇文章:ICM20948 DMP代码详解(53) 上一回解析了inv_icm20948_compass_dmp_cal函数的大部分代码,本回继续讲解inv_icm20948_compass_dmp_cal函数的余下内容。为了便于理解和回顾,再次贴出inv_icm20948_compass_dmp_cal函数代码,在EMD-Core\sources\Invn\Devices\Dri…...
RabbitMQ的应用问题
一、幂等性保障 幂等性是数学和计算机科学中某些运算的性质, 它们可以被多次应⽤, ⽽不会改变初始应⽤的结果 数学上的幂等性: f(x)f(f(x)) |x| 数据库操作幂等性: 数据库的 select 操作. 不同时间两次查询的结果可能不同, 但是这个操作是符合幂等性…...
C++14:通过make_index_sequence实现将tuple转换为array
如何将vector转换为array呢 #include <iostream> #include <tuple> #include <array> using namespace std;template <typename V, typename... Types, size_t... I> constexpr auto do_tuple_to_array(tuple<V, Types...>&& tuple, in…...
Linux中修改MySQL密码
Linux中MySQL的密码操作 1、给用户设置/更新密码 mysqladmin -u用户名 -p原密码 password "新密码"该命令在终端直接执行,不需要进入mysql视图 该命令适用于以下情况: 用户的密码为空,为用户设置密码用户密码需要更新,…...
华为OD真题机试-英文输入法(Java)
华为OD机试真题中的“英文输入法”题目主要考察的是字符串处理、单词提取、以及基于前缀的单词联想功能。以下是对该题目的详细解析: 题目描述 主管期望你来实现英文输入法单词联想功能。具体需求如下: 依据用户输入的单词前缀,从已输入的…...
【React 】入门Day01 —— 从基础概念到实战应用
目录 一、React 概述 二、开发环境创建 三、JSX 基础 四、React 的事件绑定 五、React 组件基础使用 六、组件状态管理 - useState 七、组件的基础样式处理 快速入门 – React 中文文档 一、React 概述 React 是什么 由 Meta 公司开发,是用于构建 Web 和原生…...
2024年9月总结及随笔之丢卡
1. 回头看 日更坚持了639天。 读《软件开发安全之道:概率、设计与实施》更新完成读《软件设计的要素》开更并更新完成读《构建可扩展分布式系统:方法与实践》开更并更新完成读《数据湖仓》开更并持续更新 2023年至2024年9月底累计码字1555996字&#…...
sql语法学习 sql各种语法 sql增删改查 数据库各种操作 数据库指令
sql语法学习 sql各种语法 sql增删改查 数据库各种操作 数据库指令 学习SQL语法时,理解其基本结构和用法是关键。下面是SQL语法的详细学习指南,涵盖了SQL的主要部分,包括查询、插入、更新、删除、表操作等。 1. 基本查询语法 SQL 的查询语句…...
鸡兔同笼,但是线性代数
灵感来自:bilibili,巨佬! 我们有 14 14 14 个头, 32 32 32 只脚,所有鸡和兔都没有变异,头和脚都完整,没有数错。还有什么 Bug 吗 小学奥数 假设全是鸡,则有 14 2 28 14 \time…...
01---java面试八股文——springboot---10题
01-你是怎么理解Spring Boot 的约定优于配置 约定优于配置是一种软件设计的范式,它的核心思想是减少软件开发人员对于配置项的维护,从而让开发人员更加聚焦在业务逻辑上。Spring Boot 就是约定优于配置这一理念下的产物,它类似于 Spring 框架…...
花都网站(建设信科网络)/福州网站建设方案外包
计算机体系结构可以类比人类社会的构成: 以helloworld为例,我们常见的helloworld程序背后发生了什么?这里我们详尽,完整的梳理一下整个过程,加深对计算机体系结构的理解: caozilong@caozilong-Vostro-3268:~/Workspace/helloworld$ gcc main.c caozilong@caozilong-Vos…...
做网站教学书/推广平台怎么找客源
Tomcat对于J2EE或Java web开发者而言绝不陌生,但说到Realm,可能有些人不太清楚甚至没有听说过,那么到底什么是Realm?简单一句话就是:Realm是Tomcat中为web应用程序提供访问认证和角色管理的机制。配置了Realmÿ…...
泉州做网站公司/网络推广电话销售技巧和话术
SQL数据库语言解释 COLUMN_SCHOOL_ID " interger," 切记表名和列名还有列名和类型要空格隔开并且结尾要加逗号。 一般drop table if exists是数据库里面的,后面接表名如:drop table if exists xxx_book 如果数据库中存在xxx_book表&…...
wordpress pdf 加密/网络整合营销理论案例
本文通过介绍 Linux 系统工具(Ftkimage、xmount、Volatility、dd、netcat)来介绍使用计算机取证的方法和步骤。 硬盘数据的取证是指为了证据保全,确保取证工作造成数据丢失,在获取到证据介质后,首先要做的就是对介质数…...
公众号做微网站吗/中国足球世界排名
1-1.Window下安装Python 1.安装源程序的选择: https://www.python.org/选择Python2.7X或3.5X,后者不向下兼容;选择合适自己电脑的版本进行下载,64位还是32位;2.配置环境变量:点击“我的电脑”--右键--”属性“--”高级…...
网络营销推广的重要性/营销网站seo推广
推荐书籍 等我把《笨办法学Python》学完后,就重返Python3,好好学习一下这本书。...