当前位置: 首页 > news >正文

问:JAVA阻塞队列实现类及最佳实践?

在多线程编程中,阻塞队列作为一种关键的数据结构,为线程间安全、高效的数据交换提供了重要支持。Java的java.util.concurrent包中提供了多种阻塞队列的实现,每种实现都有其独特的特点和适用场景。

一、阻塞队列实现类

以下是Java中BlockingQueue接口的主要实现类及差异。

实现类队列结构容量特性公平性支持元素特性特殊功能
ArrayBlockingQueue数组有界,创建时指定且不可变支持无特殊要求
LinkedBlockingQueue链表可选有界,动态调整容量不支持无特殊要求
PriorityBlockingQueue无界无界不支持必须实现Comparable或提供Comparator优先级排序
DelayQueue无界无界不支持必须实现Delayed接口延时获取元素
SynchronousQueue不存储元素无容量概念支持无特殊要求插入与获取操作必须配对
LinkedTransferQueue链表无界不支持无特殊要求直接传输元素给消费者
ConcurrentLinkedQueue(非BlockingQueue链表无界不适用无特殊要求非阻塞,高效并发操作
1. 队列结构
  • ArrayBlockingQueue:采用数组结构,是唯一的数组结构实现。数组结构在访问速度上通常较快,但在插入和删除元素时,可能需要移动大量数据。
  • LinkedBlockingQueuePriorityBlockingQueueDelayQueueLinkedTransferQueue:均采用链表结构。链表结构在插入和删除元素时,通常只需要修改指针,因此效率较高。
  • ConcurrentLinkedQueue:虽然也是链表结构,但它不是BlockingQueue接口的实现,而是提供了非阻塞的并发操作。
2. 容量特性
  • ArrayBlockingQueue:容量在创建时指定且不可变,因此在使用过程中需要合理设置容量大小。
  • LinkedBlockingQueue:容量可以动态调整,通过指定Integer.MAX_VALUE可以创建无界队列。这使得它在处理不确定数量的任务时更加灵活。
  • PriorityBlockingQueueDelayQueue:均为无界队列,没有容量限制。这可能会导致在内存紧张的情况下出现内存溢出的问题。
  • SynchronousQueue:不存储元素,因此没有容量概念。它要求插入与获取操作必须配对,否则线程会阻塞。
  • ConcurrentLinkedQueue:也是无界的,但它是非阻塞的,因此不会出现阻塞等待的情况。
3. 公平性支持
  • ArrayBlockingQueueSynchronousQueue:支持公平的访问队列。这意味着线程可以按照它们加入队列的顺序来访问队列中的元素,从而避免了“饥饿”现象。
  • 其他实现类均不支持公平的访问队列,这可能会导致某些线程长时间得不到执行的机会。
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阻塞队列实现类及最佳实践?

在多线程编程中&#xff0c;阻塞队列作为一种关键的数据结构&#xff0c;为线程间安全、高效的数据交换提供了重要支持。Java的java.util.concurrent包中提供了多种阻塞队列的实现&#xff0c;每种实现都有其独特的特点和适用场景。 一、阻塞队列实现类 以下是Java中Blocking…...

Springboot3 + MyBatis-Plus + MySql + Vue + ProTable + TS 实现后台管理商品分类(最新教程附源码)

Springboot3 MyBatis-Plus MySql Uniapp 商品加入购物车功能实现&#xff08;针对上一篇sku&#xff09; 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系统提升运营效率与竞争力

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

算法记录——树

二叉树 3.1二叉树的最大深度 思路&#xff1a;二叉树的最大深度 根节点的最大高度。因此本题可以转换为求二叉树的最大高度。 而求高度的时候应该采用后序遍历。遍历顺序为&#xff1a;左右中。每次遍历的节点按后序遍历顺序&#xff0c;先收集左右孩子的最大高度&#xff0c;…...

单片机在控制和自动化任务中的应用场景广泛

单片机在控制和自动化任务中的应用场景广泛&#xff0c;以下是一些具体示例&#xff1a; 1. 家电控制 洗衣机&#xff1a;单片机用于控制洗衣周期、温度和水位。微波炉&#xff1a;控制加热时间、功率和用户界面。 2. 工业自动化 生产线监控&#xff1a;单片机用于控制传送…...

UEFI EDK2框架学习(三)——protocol

一、Protocol协议 搜索支持特定Protocol的设备&#xff0c;获取其Handle gBS->LocateHandleBuffer 将内存中的Driver绑定到给定的ControllerHandle gBS->OpenProtocol 二、代码实现 Protocol.c #include <Uefi.h> #include <Library/UefiLib.h> #includ…...

PostgreSQL的字段存储类型了解

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

CTFshow 命令执行 web29~web36(正则匹配绕过)

目录 web29 方法一&#xff1a;include伪协议包含文件读取 方法二&#xff1a;写入文件 方法三&#xff1a;通识符 web30 方法一&#xff1a;filter伪协议文件包含读取 方法二&#xff1a;命令执行函数绕过 方法三&#xff1a;写入文件 web31 方法一&#xff1a;filter伪…...

【顺序表使用练习】发牌游戏

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

1.7 编码与调制

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

004集—— txt格式坐标写入cad(CAD—C#二次开发入门)

如图所示原始坐标格式&#xff0c;xy按空格分开&#xff0c;将坐标按顺序在cad中画成多段线&#xff1a; 坐标xy分开并按行重新输入txt&#xff0c;效果如下&#xff1a; 代码如下 &#xff1a; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Runtime; us…...

CSS中的font-variation-settings:探索字体的可变性

随着Web字体的发展&#xff0c;设计师们不再局限于传统的字体样式。现代Web字体支持可变字体&#xff08;Variable Fonts&#xff09;&#xff0c;这种字体允许开发者在单一的字体文件中包含多种字形样式。通过使用CSS中的font-variation-settings属性&#xff0c;我们可以控制…...

组合优化与凸优化 学习笔记5 对偶拉格朗日函数

有的时候约束条件有点难搞&#xff0c;我们可以把它放到目标函数里面。 记得之前凸函数的时候的结论吗&#xff1f;一大堆函数&#xff0c;每一段都取最大的&#xff0c;最后会得到一个凸函数。同理&#xff0c;每一段都取最小的&#xff0c;得到的是一个凹函数。就这样&#x…...

监控易监测对象及指标之:Exchange邮件服务器监测

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

【机器学习基础】Transformer学习

Transformer学习 梯度消失FeedForward层激活函数的主要作用是在网络中加入非线性变换 梯度消失 梯度爆炸 FeedForward层 Transformer结构: Transformer结构主要分为两大部分: 一是Encoder层结构:Encoder 的输入由 Input Embedding 和 Positional Embedding 求和输入Multi…...

mysql如何不使用窗口函数,去统计出入库情况

mysql如何不使用窗口函数&#xff0c;去统计出入库情况 你把这个表看做 进出库表&#xff0c;每个物料把时间正序后 依次累加数量 &#xff0c;看这个物料的时间线上 是否会出现负数&#xff0c;1号进货5个 2号出库3个 3号你不能出库3个 最多俩个 不然就是负库存&#xff0c;…...

uni-app canvas文本自动换行

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

【设计模式-职责链】

定义 职责链模式是一种行为设计模式&#xff0c;**它通过将请求发送给链上的多个处理者来避免请求发送者与处理者之间的紧密耦合。每个处理者可以选择处理请求或将其传递给链中的下一个处理者。**这样&#xff0c;可以将处理请求的责任链式组织&#xff0c;从而实现更灵活的请…...

Prompt:在AI时代,提问比答案更有价值

你好&#xff0c;我是三桥君 随着AI技术的飞速发展&#xff0c;我们进入了一个信息爆炸的时代。在这个时代&#xff0c;只要你会提问&#xff0c;AI就能为你提供满意的答案。这种现象让很多人开始思考&#xff1a;在这个答案触手可及的时代&#xff0c;答案的价值是否还像以前…...

whatis命令:关于命令的简短描述

一、命令简介 ​whatis​ 命令用于查询命令、函数、文件等的基本用途&#xff0c;查询结果只是一句简短的描述。 例如 $ whatis ls ls (1) - list directory contents返回关于 ls 命令的简短描述。这个结果实质是来自于man手册的一个章节&#xff0c;在较新的L…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...