Java并发基础:LinkedBlockingDeque全面解析!
内容概要
LinkedBlockingDeque
提供了线程安全的双端队列实现,它支持在队列两端高效地进行插入和移除操作,同时具备阻塞功能,能够很好地协调生产者与消费者之间的速度差异,其内部基于链表结构,使得并发性能优异,是处理多线程间数据传递的理想选择。
核心概念
LinkedBlockingDeque
实现了一个线程安全的双端队列(Deque,即 double-ended queue),这个队列在两端都可以添加和移除元素,而且它是阻塞的,意味着当队列为空时,如果线程尝试从队列中取元素,线程会被阻塞,直到队列中有元素可供取出;同样地,如果队列已满,尝试添加元素的线程也会被阻塞,直到队列中有空间可供添加新元素。
举一个生活中的实际案例,比如一个面包店,面包师傅负责生产面包(生产者),顾客来店里买面包(消费者),面包师傅做好面包后,会把它们放在一个展示架上供顾客挑选;顾客则从这个展示架上取走他们想要的面包,这里使用LinkedBlockingDeque
来模拟这个场景。面包师傅(生产者线程)在队列的一端放入新做好的面包(添加元素到队列),而顾客(消费者线程)从队列的另一端取走面包(从队列中移除元素):
- 阻塞特性:如果展示架上没有面包(队列为空),顾客就会被阻塞,直到面包师傅做好新的面包并放到展示架上,同样,如果展示架满了(队列已满),面包师傅就会被阻塞,直到有顾客取走一些面包,腾出空间来放新的面包。
- 双端操作:在这个场景中,虽然通常面包师傅只在一端放面包,顾客在另一端取面包,但双端队列的灵活性意味着也可以轻松改变这个行为,比如,如果有特殊情况,面包师傅可以从展示架上取回一些面包(从队列的另一端移除元素),或者顾客可以预先把他们的面包订单放到展示架上(在队列的另一端添加元素)。
LinkedBlockingDeque
是一个线程安全的双端队列,允许从队列的两端添加和移除元素,并且它是阻塞的,他通常用来解决以下问题:
- 线程安全:在多线程环境中,当多个线程需要访问和修改共享数据时,
LinkedBlockingDeque
提供了一种线程安全的方式来存储和检索这些数据,它内部的同步机制确保了数据的一致性和完整性。 - 阻塞操作:当队列为空时,消费者线程调用
take()
方法会被阻塞,直到生产者线程向队列中添加元素,同样,当队列已满时,生产者线程调用put()
方法也会被阻塞,直到消费者线程从队列中移除元素,这种阻塞行为有助于防止线程在不必要的情况下空转或浪费CPU资源。 - 容量限制:
LinkedBlockingDeque
可以在创建时指定一个最大容量,这个容量限制了队列中可以存储的元素数量,有助于防止内存溢出,当队列达到最大容量时,生产者线程会被阻塞,直到队列中有空间可用。 - 双端操作:与普通的
BlockingQueue
接口实现相比,LinkedBlockingDeque
提供了双端队列的功能,允许从队列的两端添加和移除元素,这为某些特定的应用场景提供了更大的灵活性。 - 高效的并发性能:由于其内部使用链表数据结构,
LinkedBlockingDeque
在处理大量并发操作时通常具有较好的性能,它适用于需要高吞吐量和低延迟的生产者-消费者场景。
代码案例
下面是一个简单的例子,演示了如何使用 LinkedBlockingDeque
类,如下代码:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque; public class LinkedBlockingDequeExample { public static void main(String[] args) throws InterruptedException { // 创建一个容量为 5 的 LinkedBlockingDeque BlockingQueue<String> deque = new LinkedBlockingDeque<>(5); // 启动一个生产者线程,向队列中添加元素 Thread producer = new Thread(() -> { try { for (int i = 0; i < 10; i++) { String item = "Item-" + i; deque.put(item); // 当队列满时,该方法会阻塞 System.out.println("Produced: " + item); Thread.sleep(200); // 模拟生产延迟 } } catch (InterruptedException e) { e.printStackTrace(); } }); // 启动一个消费者线程,从队列中移除元素 Thread consumer = new Thread(() -> { try { for (int i = 0; i < 10; i++) { String item = deque.take(); // 当队列空时,该方法会阻塞 System.out.println("Consumed: " + item); Thread.sleep(300); // 模拟消费延迟 } } catch (InterruptedException e) { e.printStackTrace(); } }); // 启动生产者和消费者线程 producer.start(); consumer.start(); // 等待两个线程执行完成 producer.join(); consumer.join(); System.out.println("Producer and Consumer threads have finished."); }
}
在上面代码中,创建了一个 LinkedBlockingDeque
实例,并指定了它的最大容量为 5,然后创建了一个生产者线程和一个消费者线程,生产者线程将循环 10 次,每次生产一个字符串并将其放入队列中,如果队列已满,put
方法将会阻塞直到队列中有空间可用,消费者线程也将循环 10 次,每次从队列中取出一个元素并打印它,如果队列为空,take
方法将会阻塞直到队列中有元素可取。
由于生产者和消费者线程的速度可能不同,LinkedBlockingDeque
作为一个阻塞队列,能够协调这两个线程之间的速度差异,确保它们可以协同工作,而不会因为队列为空或满而导致任何一方停滞不前。
核心API
LinkedBlockingDeque
实现了 BlockingDeque
接口,是一个线程安全的双端队列,以下是 LinkedBlockingDeque
类中一些主要方法的含义:
- add(E e)
将指定的元素插入到此双端队列表示的队列中(即在此双端队列的尾部),如果立即可行且不会违反容量限制,则成功时返回true
,如果当前没有可用的空间,则抛出IllegalStateException
,这是Queue
接口的方法。 - offer(E e)
将指定的元素插入到此双端队列表示的队列中(即在此双端队列的尾部),如果立即可行且不会违反容量限制,则成功时返回true
,如果当前没有可用的空间,则返回false
,这是Queue
接口的方法。 - put(E e) throws InterruptedException
将指定的元素插入到此双端队列表示的队列中(即在此双端队列的尾部),必要时将等待空间变得可用,这是BlockingQueue
接口的方法。 - offer(E e, long timeout, TimeUnit unit)
将指定的元素插入到此双端队列表示的队列中,必要时将等待指定的时间以使空间变得可用,这是BlockingQueue
接口的方法。 - remove()
获取并移除此双端队列表示的队列的头部,如果此双端队列为空,则抛出NoSuchElementException
,这是Queue
接口的方法。 - poll()
获取并移除此双端队列表示的队列的头部,如果此双端队列为空,则返回null
,这是Queue
接口的方法。 - take() throws InterruptedException
获取并移除此双端队列表示的队列的头部,在元素变得可用之前一直等待,这是BlockingQueue
接口的方法。 - poll(long timeout, TimeUnit unit)
获取并移除此双端队列表示的队列的头部,在指定的时间内等待元素变得可用,这是BlockingQueue
接口的方法。 - peek()
获取但不移除此双端队列表示的队列的头部,如果此双端队列为空,则返回null
,这是Queue
接口的方法。 - element()
获取但不移除此双端队列表示的队列的头部,这是Queue
接口的方法。 - push(E e)
将元素推入此双端队列表示的堆栈中(即在此双端队列的头部),如果立即可行且不会违反容量限制,则成功时返回true
,如果当前没有可用的空间,则抛出IllegalStateException
。 - pop()
从此双端队列表示的堆栈中弹出一个元素,如果此双端队列为空,则抛出NoSuchElementException
。 - addFirst(E e), addLast(E e)
将指定的元素插入此双端队列的开头或结尾。 - offerFirst(E e), offerLast(E e)
将指定的元素插入此双端队列的开头或结尾,如果立即可行且不会违反容量限制,则成功时返回true
,如果当前没有可用的空间,则返回false
。 - removeFirst(), removeLast()
获取并移除此双端队列的第一个元素或最后一个元素。 - pollFirst(), pollLast()
获取并移除此双端队列的第一个元素或最后一个元素,如果此双端队列为空,则返回null
。 - getFirst(), getLast()
获取但不移除此双端队列的第一个元素或最后一个元素。 - peekFirst(), peekLast()
获取但不移除此双端队列的第一个元素或最后一个元素,如果此双端队列为空,则返回null
。
核心总结
LinkedBlockingDeque
类它融合了阻塞队列和双端队列的特性,其优点在于高效的并发性能和灵活的两端操作,适合在生产者-消费者场景中使用,能够很好地处理多线程间的数据共享和传递,缺点在高并发下如果队列大小设置不当,可能会导致过多的线程阻塞,影响系统整体性能,此外,由于是基于链表的实现,其内存占用可能相对较高。
END!
往期回顾
Java并发基础:LinkedBlockingDeque全面解析!
Java并发基础:LinkedTransferQueue全面解析!
Java并发基础:LinkedBlockingQueue全面解析!
Java并发基础:Deque接口和Queue接口的区别?
Spring核心基础:全面总结Spring中提供的那些基础工具类!
相关文章:

Java并发基础:LinkedBlockingDeque全面解析!
内容概要 LinkedBlockingDeque提供了线程安全的双端队列实现,它支持在队列两端高效地进行插入和移除操作,同时具备阻塞功能,能够很好地协调生产者与消费者之间的速度差异,其内部基于链表结构,使得并发性能优异&#x…...

Zabbix6.x配置中文界面 解决乱码问题
Zabbix6.x配置中文界面 解决乱码问题 Zabbix6.x界面无法选择中文,通过安装语言包解决。后面也解决了zabbix6中文方块(乱码)问题。 配置中文语言包 系统中默认没有携带中文语言包,可以通过以下命令查看 localectl list-locales #…...

next项目页面性能调优
next项目页面性能调优 一般来说性能优化可以分为加载时、运行时两部分的优化。 扩展参考链接: 前端性能优化 24 条建议 Webpack 4进阶–从前的日色变得慢 ,一下午只够打一次包 Webpack 分包优化首屏加载 参考指标 FCP(First Contentful P…...

性能评测|虚拟化和裸金属 K8s 哪个性能更好?
本文重点 整体而言,SKS(虚拟机 Kubernetes)可以达到裸金属 Kubernetes 性能的 82% – 96%,满足绝大部分场景下生产容器应用的性能需求。更多虚拟化与裸金属 Kubernetes 架构、特性、适用场景与性能对比,欢迎阅读文末电…...

【大厂AI课学习笔记】【1.6 人工智能基础知识】(1)人工智能、机器学习、深度学习之间的关系
6.1 人工智能、机器学习与深度学习的关系 必须要掌握的内容: 如上图:人工智能>机器学习>深度学习。 机器学习是人工智能的一个分支,该领域的主要研究对象是人工智能,特别是如何在经验学习中改进具体算法的性能。 深度学习…...

计算机毕业设计基于的农村蔬菜销售系统SSM
项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: vue mybatis Maven mysql5.7或8.0等等组成,B…...

【Chrono Engine学习总结】3-地型terrain
由于Chrono的官方教程在一些细节方面解释的并不清楚,自己做了一些尝试,做学习总结。 1、关于物体材质 在介绍地型之前,要初步了解chrono中关于材质的一些基本概念。 首先,最基本的材质类是ChMaterialSurface,其进一步包括&…...

【Linux】构建模块
🔥博客主页:PannLZ 🎋系列专栏:《Linux系统之路》 🥊不要让自己再留有遗憾,加油吧! 文章目录 构建第一个模块1模块的makefile2内核树内构建3内核树外构建 构建第一个模块 可以在两个地方构建模…...

vscode远程连接失败
目录 解决方案尝试1解决方案尝试2 解决方案尝试1 最近通过vscode一直使用腾讯云的服务器作为远程开发环境,以前一直很好用。 直到最近重装了系统之后,发现vscode没法对云服务器进行连接了,即使在远程主机添加了本地的公钥也不行。直接报错:…...
C#系列-C#访问FTP服务器实现上传下载(8)
FTP Server是什么? FTP Server(File Transfer Protocol Server),即文件传输协议服务器,是在互联网上提供文件存储和访问服务的计算机。它依照FTP协议提供服务,专门用来传输文件。 FTP Server允许不同的客…...
django中实现登录
Django中实现登录功能,通常涉及以下几个步骤: 一:实现步骤 1:创建用户模型:Django自带了一个用户认证系统,通常使用内置的User模型来管理用户。你也可以根据需要自定义用户模型。 2:创建登录表…...
【安卓操作系统——讲解】
安卓操作系统 安卓操作系统 安卓操作系统 安卓(Android)是一种基于Linux内核和其他开源软件的移动操作系统,主要用于触屏移动设备如智能手机和平板电脑。由Andy Rubin等人开发,最初的目的是创建一个先进的操作系统,用…...
Linux发行版全景:选择、使用和未来趋势
1. 引言 Linux操作系统的简介 Linux是一种自由和开源的操作系统内核,由Linus Torvalds在1991年首次发布。随着时间的发展,Linux已经成为世界上最流行的操作系统之一,广泛用于服务器、桌面电脑、移动设备以及嵌入式系统。Linux的主要特点是其…...
STM32 与 ARM 的联系
STM32 和 ARM 是两个不同的概念,但它们之间存在一定的联系。 STM32是一种微控制器产品,由意法半导体(STMicroelectronics)推出,其内核采用了 ARM Cortex-M 核。ARM 是一家英国芯片设计公司,专注于设计和许可…...

每日五道java面试题之java基础篇(二)
第一题. 为什么说 Java 语⾔“编译与解释并存”? ⾼级编程语⾔按照程序的执⾏⽅式分为编译型和解释型两种。 简单来说,编译型语⾔是指编译器针对特定的操作系统将源代码⼀次性翻译成可被该平台执⾏的机器码;解释型语⾔是指解释器对源程序逐…...

【Linux】Shell编程
Shell编程 目录 Shell编程1.shell基础1.输入重定向 & 输出重定向2.管道3.特殊字符(3.1)通配符(3.2)引号(3.3)注释符(#) 4.别名5.命令历史history 2.Shell脚本Shell脚本的执行方式(1)为脚本文件加上可执行权限,然后在命令行直接输入shell脚本文件名执行。(2)sh shell脚本名(…...

斯巴鲁Subaru EDI需求分析
斯巴鲁Subaru是日本运输集团斯巴鲁公司(前身为富士重工)的汽车制造部门,以性能而闻名,曾赢得 3 次世界拉力锦标赛和 10 次澳大利亚拉力锦标赛。 斯巴鲁Subaru EDI 需求分析 企业与斯巴鲁Subaru建立EDI连接,首先需要确…...
golang 集成sentry:PostgreSQL
本文介绍通过 pgx库集成sentry, pgx 特点是速度快,可以完全控制,并且支持所有 postgres 数据类型。 pgx地址: https://github.com/jackc/pgx 最简单的接入方式是自定义一个logger, 然后注入到pgx, 完整示…...

ubuntu20.04 安装mysql(8.x)
安装mysql命令 sudo apt-get install mysql-server安装完毕后,立即初始化密码 sudo mysql -u root # 初次进入终端无需密码ALTER USER rootlocalhost IDENTIFIED WITH caching_sha2_password BY yourpasswd; # 设置本地root密码设置mysql远程登录 设置远程登录账…...
ChatGPT升级至GPT-4 Turbo:性能升级同时更为经济
ChatGPT升级至GPT-4 Turbo:性能升级同时更为经济 随着技术的进步,ChatGPT迎来了其最新的迭代版本——GPT-4 Turbo。这一最新版本不仅在性能上得到了显著提升,而且在成本效益上也更加引人注目。 性能提升 GPT-4 Turbo带来了诸多改进&#x…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...

Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...