【Java】阻塞队列

目录

BlockingQueue

BlockingQueue接口

三个主要实现类介绍:

ArrayBlockingQueue:有界队列

LinkedBlockingQueue:无界队列

SynchronousQueue:同步队列

队列对比


BlockingQueue


  对于Queue而言,BlockingQueue是主要的线程安全的版本,具有阻塞功能,可以允许添加、删除元素被阻塞,直到成功为止,BlockingQueue相对于Queue而言增加了两个方法put、take元素。

BlockingQueue接口


属于并发容器中的接口,在java.util.concurrent包路径下
BlockingQueue不接受null元素,加入尝试通过add、put、offer等添加一个null元素时,某些实现上会抛出nullpointExeception问题。
BlockingQueue是可以指定容量,如果给定的数据超过给定容量,便无法添加元素,如果没有指定容量约束,最大大小是Interger.MAX_VALUE值
BlockingQueue实现类主要用于生产者-消费者队列,另支持Collection接口。
BlockingQueue实现了线程安全,所有排队方法都可以使用内部锁或者其他并发控制形式来达到线程安全的目的。

三个主要实现类介绍:

ArrayBlockingQueue:有界阻塞队列
LinkedBlockingQueue:无界阻塞队列
SynchronousQueue: 同步队列


ArrayBlockingQueue:有界队列


ArrayBlockingQueue有界队列底层实现是数组,数组大小是固定的,假如数组一端为头,另一端为尾,那么头和尾构建一个FIFO队列

属性和默认值:

   

//存储的数据 存放在数组中final Object[] items;//读数据位置int takeIndex;//写入数据位置int putIndex;//数据数量int count;//队列同步相关属性final ReentrantLock lock;private final Condition notEmpty;private final Condition notFull;

 
通过ArrayBlockingQueue数据结构可知:首先是有一个数组T[],用来存储所有的元素,由于ArrayBlockingQueue最终设置为一个不可扩展大小的Queue,所以这里items就是初始化就固定大小的数组(final),另外有两个索引,头索引takeIndex,尾索引putIndex,一个队列的大小count,要阻塞的话就必须用到一个锁和两个条件(非空,非满),这三个条件都是不可变类型。因为只有一把锁,所以任意时刻对队列只能有一个线程,意味着索引和大小的操作都是线程安全的,所以可以看到takeindex等不需要原子操作和volatile语义了。

构造函数:

 public ArrayBlockingQueue(int capacity) {this(capacity, false);}//通过初始容量和是否公平性抢锁标志来进行实例化public ArrayBlockingQueue(int capacity, boolean fair) {if (capacity <= 0)throw new IllegalArgumentException();this.items = new Object[capacity];lock = new ReentrantLock(fair);notEmpty = lock.newCondition();notFull =  lock.newCondition();}//通过初始容量capacity、公平性标志fair和集合cpublic ArrayBlockingQueue(int capacity, boolean fair,Collection<? extends E> c) {this(capacity, fair);final ReentrantLock lock = this.lock;lock.lock(); // Lock only for visibility, not mutual exclusiontry {int i = 0;try {for (E e : c) {//数据是不能为nullcheckNotNull(e);items[i++] = e;}} catch (ArrayIndexOutOfBoundsException ex) {throw new IllegalArgumentException();}count = i;putIndex = (i == capacity) ? 0 : i;} finally {lock.unlock();}}

put操作

可阻塞的添加元素

 

 public void put(E e) throws InterruptedException {//检测插入数据不能为nullcheckNotNull(e);//添加可中断的锁final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {while (count == items.length) //容量满了需要阻塞notFull.await();//当前集合未满,执行插入操作insert(e);} finally {//释放锁lock.unlock();}}private void insert(E x) {items[putIndex] = x;putIndex = inc(putIndex);++count;//通知take操作已经有数据吗,如果有take方法阻塞,此时可被唤醒来执行take操作notEmpty.signal();}//循环数组的特殊标志处理 ,如果是到最大值则重定向到0号索引final int inc(int i) {return (++i == items.length) ? 0 : i;}

插入操作,在队列满的情况下会阻塞,直到有数据take出队列时才能结束阻塞,将当前数据插入队列。

take方法

 

    public E take() throws InterruptedException {//添加可中断的锁final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {while (count == 0) //队列中没有数据时,需要阻塞,直到有数据put进入队列通知该操作可以继续执行notEmpty.await();//有数据时return extract();} finally {//释放锁lock.unlock();}}private E extract() {final Object[] items = this.items;E x = this.<E>cast(items[takeIndex]);items[takeIndex] = null;takeIndex = inc(takeIndex);--count;//发出通知 通知put方法,唤醒put操作notFull.signal();return x;}

ArrayBlockingQueue特点:
1、底层数据结构是数组,且数组大小一旦确定不可更改
2、不能存储null
3、阻塞功能是通过一个锁和两个隶属于该锁的Condition进行通信完成阻塞

LinkedBlockingQueue:无界队列


LinkedBlockingQueue有两个lock锁和两个Condition以及用于计数的AtomicInteger
底层数据结构是链表,都是采用头尾节点,每个节点执行下一个节点的结构
数据存储在Node结构中。
引入两把锁,一个入队列锁,一个出队列的锁。满足同时有一个队列不满的Condition和一个队列不空的Condition。
为什么使用两把锁,一把锁是否可以?
一把锁完全可以的,一把锁意味着入队列和出队列同时只能有一个在进行,另一个必须等待释放锁,而从实际实现上来看,head和last是分离的,相互独立的,入队列实现是不会修改出队列的数据的,同理,出队列时也不会修改入队列的数据,这两个操作实际是相互独立,这个锁相当于两个写入锁,入队列是一种写操作,操作head,出队列是一种写操作,操作的是tail,这两是无关的。

SynchronousQueue:同步队列


SynchronousQueue为同步队列:每个插入操作必须等待另一个线程的移除操作,同样,任何一个移除操作都要等待另一个线程的插入操作,因此此队列中其实没有任何一个数据,或者说容量为0,SynchronousQueue更像一个管道,不像容器,资源从一个方向快速的传递到另一个方向。

队列对比

如果不需要阻塞队列,优先选择ConcurrentLinkedQueue;
如果需要阻塞队列,队列大小固定优先选择ArrayBlockingQueue;
队列大小不固定优先选择LinkedBlockingQueue;
如果需要对队列进行排序,选择PriorityBlockingQueue;
如果需要一个快速交换的队列,选择SynchronousQueue;
如果需要对队列中的元素进行延时操作,则选择DelayQueue。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/663069.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

有深浅入数据分析 - 启发法(凭人类的天性做分析)

在做数据分析的时候&#xff0c;往往最优的方法是艰难耗时间的 凭经验处理&#xff0c;迅速做出决策&#xff0c;确识能够奏效&#xff0c;进行数据分析的重要而必要的技能 领导的要求是&#xff1a; 邋遢集的处理方式是&#xff1a; 计量的方式处理 上图的调查问卷可以…

pytorch模型里 safetensors 文件、bin文件和pth文件区别、加载和保存方式

目录 PyTorch模型中的safetensors文件和bin文件区别 safetensors文件 bin文件 结论 区别bin文件和pth文件 1. 文件格式 2. 通用性 3. 期望内容 4. 兼容性和移植性 结论 加载和保存safetensors文件 保存safetensors文件 加载safetensors文件 加载和保存bin文件 保…

JVM 内存配置参数积累

0、简介 在进行JVM内存配置时&#xff0c;应当考虑到应用程序的实际需求和运行环境的资源限制&#xff0c;合理分配Xmx、Xms和Xmn参数&#xff0c;以获得最佳的性能表现。通常建议将Xms和Xmx设置为相同的值&#xff0c;以避免JVM在运行过程中动态调整堆大小带来的性能损耗。而…

Axure 动态面板初使用-实现简单的tab切换页面效果

使用工具版本 Axure 9 实现的效果 步骤过程 1、打开Axure 9&#xff0c;默认进入一个空白页&#xff0c;首先从元件库拉一个动态面板到页面中&#xff0c;位置肯定是C位咯~ 2、将面板尺寸调整一下&#xff0c;设置成你喜欢的数字&#xff0c;比如我就喜欢800600 3、然后…

学习日志以及个人总结(13) 指针!

指针 定义 访问内存地址 操控硬件 指针&#xff1a; 指针基本数据据类 指针数组 指针函数 指针指针 1.指针&#xff1a;就是地址-----就是内存的单元的编号 2.指针变量 语法&#xff1a; 基类型* 指针变量名&#xff1b; 基类型-------数据类型//基础数据类型 //数组…

python脚本将照片按时间线整理

说明&#xff1a;有一次自己瞎折腾&#xff0c;然后把服务器相册搞崩了&#xff0c;后来做了备份同步给找了回来&#xff0c;但是相册的时间线全乱了&#xff0c;看起来非常难受。所以就想通过文件夹的形式把照片重新分类&#xff0c;分类后的结构如下(红色字体为文件夹)&#…

item_get-根据ID取商品详情(shopee.item_get):跨境电商的未来趋势

根据您的需求&#xff0c;我为您撰写了一篇关于“item_get-根据ID取商品详情(shopee.item_get)&#xff1a;跨境电商的未来趋势”的文章。由于篇幅限制&#xff0c;我将提供文章的概要和部分内容&#xff0c;完整的文章将需要更多细节和展开。 item_get-根据ID取商品详情(shope…

《区块链简易速速上手小册》第7章:区块链在其他行业的应用(2024 最新版)

文章目录 7.1 供应链管理7.1.1 供应链管理中区块链的基础7.1.2 主要案例&#xff1a;食品安全追踪7.1.3 拓展案例 1&#xff1a;制药供应链7.1.4 拓展案例 2&#xff1a;汽车行业的零部件追踪 7.2 区块链在医疗保健中的应用7.2.1 医疗保健中区块链的基础7.2.2 主要案例&#xf…

今天聊聊软件研发部门孵化策略

声明&#xff1a;上述内容纯属个人瞎说&#xff0c;如有雷同请联系删除。 引&#xff1a;公司研发二部的同事召回来了&#xff0c;这边先恭喜他们荣耀而归。大家都欢心鼓舞、人事嘘寒问暖、综合端盘倒水&#xff1b;真热闹……。我们部门的同事就在边上办公&#xff0c;感触很深…

如何处理缓存一致性问题

* 如何解决缓存一致性问题 * 1. 更新缓存 * ①先更新缓存&#xff0c;再更新数据库. 如果先更新缓存成功了&#xff0c;但是更新数据库失败了&#xff0c;那么数据库将出现脏数据&#xff0c;否掉 * ②先更新数据库&#xff0c;再更新缓存. 如果先更新数据库&#xff0c;但更…

1451A/D/F捷变信号发生器

01 1451A/D/F捷变信号发生器 产品综述&#xff1a; 1451系列捷变信号发生器采用直接数字合成&#xff08;DDS&#xff09;技术和直接模拟合成技术&#xff08;ADS&#xff09;相结合的设计方案&#xff0c;实现覆盖10MHz~3/20/40GHz全频段的频率捷变&#xff0c;捷变时间小于…

UMI初始化脚手架 Simple App、 Ant Design Pro、Vue Simple App、Umi Plugin 4者的区别

这四个概念分别代表不同的工具和框架&#xff0c;它们的主要区别如下&#xff1a; Simple App&#xff1a;这通常指的是一个基础的、最小化的应用程序。它可能只包含最基础的功能&#xff0c;如用户界面、一些简单的交互等。这种应用程序通常用于学习和实验目的&#xff0c;或者…

分布式事务(四)——TCC补偿模式解决方案

系列目录&#xff1a; 《分布式事务&#xff08;一&#xff09;—— 事务的基本概念》 《分布式事务&#xff08;二&#xff09;—— CAP和Base理论》 《分布式事务&#xff08;三&#xff09;—— 两阶段提交解决方案&#xff08;2PC&#xff09;》 一、常见分布式事务解决…

Android selinux调试(rk3588 android 12平台)

Android selinux调试(rk3588 android 12平台)&#xff1a; 参考文档&#xff1a; Android系统10 RK3399 init进程启动(二十七) Selinux Type和Attribute https://www.jb51.net/article/277418.htm Android selinux策略文件的编译与加载 https://c.biancheng.net/view/1151.h…

WPF DataTemplate内重写BorderBrush,VisualBrush内数据源绑定提示绑定失败

定义DataTemplate 数据模板文件&#xff0c;内容如下 <DataTemplate x:Key"{DataTemplateKey {x:Type VM:TemplateListVM}}" DataType"{x:Type VM:TemplateListVM}"> <Grid Margin"0" Grid.Row"3" Height"50" Ver…

python:lxml 生成思维导图 Freemind(.mm)文件

请参阅&#xff1a;从PDF中提取目录 或者 java : pdfbox 读取 PDF文件内书签 pip install lxml ; lxml-5.1.0-cp310-cp310-win_amd64.whl (3.9 MB) 读目录.txt文件&#xff0c;使用 lxml 生成思维导图 Freemind&#xff08;.mm&#xff09;文件 编写 txt_etree_mm.py 如下…

QML自定义ComboBox组件,支持动态筛选

QtQuick.Controls提供了ComboBox组件&#xff0c;该组件能够满足日常的下拉选择框的需求&#xff0c;但当需要用户在ComboBox中通过输入关键字进行自动匹配时&#xff0c;原生的组件虽然提供了editable属性用于输入关键字&#xff0c;但是匹配内容不弹出下拉框&#xff0c;无法…

03、全文检索 -- Solr -- Solr 身份验证配置(给 Solr 启动身份验证、添加用户、删除用户)

目录 全文检索 -- Solr -- Solr 身份验证配置启用身份验证&#xff1a;添加用户&#xff1a;删除用户&#xff1a; 全文检索 – Solr – Solr 身份验证配置 学习之前需要先启动 Solr 执行如下命令即可启动Solr&#xff1a; solr start -p <端口>如果不指定端口&#xf…

7-2.递归思想代码练习题

例题1.按顺序打印一个数据的每一位 1234 输出 1 2 3 4 解决问题的思路 如何拿到这个数的每一位 1234%104 1234/10123 123%103 123/1012 12%102 12/101 1%101 递推公式&#xff1a;%10 /10 初始条件&#xff1a;1-9之间的数直接打印&#xff08;n<10&#xff09; n>10 进行…

最近nvm安装报错的原因找到了——npm原淘宝镜像正式到期!

前言 &#x1f4eb; 大家好&#xff0c;我是南木元元&#xff0c;热爱技术和分享&#xff0c;欢迎大家交流&#xff0c;一起学习进步&#xff01; &#x1f345; 个人主页&#xff1a;南木元元 目录 背景 错误原因 问题排查 淘宝镜像 证书到期 问题解决 结语 背景 我们…