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

java并发编程 PriorityBlockingQueue详解

文章目录

  • 1 PriorityBlockingQueue是什么
  • 2 核心属性详解
  • 3 核心方法详解
    • 3.1 offer(E e)
    • 3.2 poll()
    • 3.3 take()
    • 3.4 peek()
  • 4 总结


1 PriorityBlockingQueue是什么

PriorityBlockingQueue类上的注释描述:一个无界阻塞队列,它使用与类PriorityQueue相同的排序规则,并提供阻塞检索操作。
PriorityQueue又是什么:基于优先级的 堆 的无限制优先级队列,PriorityQueue是一个小顶堆。

2 核心属性详解

利用数组实现小顶堆,利用ReentrantLock 保证元素插入和移除的线程安全。同时因为是无界队列,所以需要扩容机制,此时引入遍历allocationSpinLock 对他unsafe的cas操作,表示谁去扩容。

	//元素存放的集合容器,堆结构也是个数组,所以需要数组集合private transient Object[] queue;//元素的数量private transient int size;//指定的元素的比较规则private transient Comparator<? super E> comparator;//保证线程安全的锁private final ReentrantLock lock;//当获取元素的线程因为集合中无元素而阻塞,会使用该等待条件去实现private final Condition notEmpty;/*** 扩容时候使用的cas锁,因为扩容要保证线程安全,数组扩容是要new一个新数组的*/private transient volatile int allocationSpinLock;//序列化和反序列化使用的private PriorityQueue<E> q;

3 核心方法详解

3.1 offer(E e)

put操作一样,因为无界队列,所以没有存在容量满了,阻塞等待获取元素的线程唤醒
整体逻辑就是元素放入堆中,如果容量不够就进行扩容,ReentrantLock 保证了这些操作是线程安全的

    public boolean offer(E e) {if (e == null)throw new NullPointerException();//获取锁final ReentrantLock lock = this.lock;lock.lock();int n, cap;Object[] array;//如果当前元素数量已经达到了数组的长度上限,则需要扩容while ((n = size) >= (cap = (array = queue).length))//对当前数组进行扩容 扩容代码下面有解释tryGrow(array, cap);try {Comparator<? super E> cmp = comparator;// 如果没指定比较器,就代表你的类实现了Comparable接口if (cmp == null)//添加元素到堆里 堆排序算法siftUpComparable(n, e, array);else//使用指定的比较器进行入堆siftUpUsingComparator(n, e, array, cmp);size = n + 1;notEmpty.signal();} finally {lock.unlock();}return true;}//扩容代码描述private void tryGrow(Object[] array, int oldCap) {//先释放锁,因为当前线程需要干扩容的活,不需要阻塞别的线程,这样可能别的线程执行到这扩容已经好了,//就可以执行if (newArray != null && queue == array) ture成立的条件了lock.unlock();Object[] newArray = null;//通过扩容锁,减小锁的粒度,只有一个线程能去开辟新的数组if (allocationSpinLock == 0 &&UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,0, 1)) {try {//当前数组长度小于64的时候长度加2,否则长度翻倍int newCap = oldCap + ((oldCap < 64) ?(oldCap + 2) : // grow faster if small(oldCap >> 1));//长度到达上限抛异常                      if (newCap - MAX_ARRAY_SIZE > 0) {// possible overflow//MAX_ARRAY_SIZE 是int最大值减8 此时还能慢慢的加,不过一般来说都会OOM了int minCap = oldCap + 1;if (minCap < 0 || minCap > MAX_ARRAY_SIZE)throw new OutOfMemoryError();newCap = MAX_ARRAY_SIZE;}//if (newCap > oldCap && queue == array)newArray = new Object[newCap];} finally {allocationSpinLock = 0;}}//此时可能线程没拿到扩容锁,且newArray = new Object[newCap];还没执行到if (newArray == null)Thread.yield();//再次获取主锁lock.lock();//此时两种情况//1.到这newArray = new Object[newCap];还没执行到,此时newArray == null,queue还没被替换,所以该方法结束之后,循环又回来了,释放锁。。。再次争抢锁//2.newArray = new Object[newCap];已执行,此时因为获取的是主锁,只有一个线程能执行底下的queue = newArray;和数组copy操作//这样,其他线程获取到锁之后就会往新的数组中添加元素了if (newArray != null && queue == array) {queue = newArray;System.arraycopy(array, 0, newArray, 0, oldCap);}}

如果队列中数组元素特别多,此时扩容一次需要的时间就会相对增加,其他线程阻塞的时间就会边长。

3.2 poll()

获取一个元素。

    public E poll() {//获取锁final ReentrantLock lock = this.lock;lock.lock();try {//拿出堆顶元素 return dequeue();} finally {lock.unlock();}}private E dequeue() {//n是当前元素结合中左后一个元素int n = size - 1;if (n < 0)return null;else {Object[] array = queue;//堆顶就是0下标E result = (E) array[0];E x = (E) array[n];array[n] = null;//堆顶被取出,此时把末尾元素拿上来去重新比较排序保证堆的完整性Comparator<? super E> cmp = comparator;if (cmp == null)siftDownComparable(0, x, array, n);elsesiftDownUsingComparator(0, x, array, n, cmp);size = n;return result;}}

3.3 take()

相对于poll 多了等待操作

public E take() throws InterruptedException {final ReentrantLock lock = this.lock;lock.lockInterruptibly();E result;try {while ( (result = dequeue()) == null)//区别在这notEmpty.await();} finally {lock.unlock();}return result;
}

3.4 peek()

获取堆顶元素,但不移除

 public E peek() {//获取锁final ReentrantLock lock = this.lock;lock.lock();try {//返回堆顶元素return (size == 0) ? null : (E) queue[0];} finally {lock.unlock();}}

4 总结

PriorityBlockingQueue是一个小顶堆的数据结构的类,使用了ReentrantLock来保证线程安全。可以通过传入的比较器去自定义小顶堆的比较规则,或者实现Comparable接口。

相关文章:

java并发编程 PriorityBlockingQueue详解

文章目录 1 PriorityBlockingQueue是什么2 核心属性详解3 核心方法详解3.1 offer(E e)3.2 poll()3.3 take()3.4 peek() 4 总结 1 PriorityBlockingQueue是什么 PriorityBlockingQueue类上的注释描述&#xff1a;一个无界阻塞队列&#xff0c;它使用与类PriorityQueue相同的排序…...

SpringMVC_基本使用

一、JavaWEB 1.回顾 JavaWEB 1.1新建项目结构 新建 javaweb 项目目录结构 1.2导入依赖 依赖 <dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>…...

大屏开发,浏览器的可视区域和设备的分辨率

在线屏幕检测 - 显示器检测 - 显示器坏点检测工具...

【微服务部署】06-日志集成

文章目录 1. EFK日志三件套集成1.1 核心组件1.2 部署 2. Exceptionless日志系统2.1 Exceptionless核心特性2.2 Exceptionless部署文件2.3 K8s中使用Exceptionless 1. EFK日志三件套集成 1.1 核心组件 Elasticsearch&#xff08;存储&#xff09;Fluentd&#xff08;收集器&am…...

【Python】python使用docxtpl生成word模板

python使用docxtpl生成word模板 python-docxtpl包简单使用和实战&#xff0c;Python处理word&#xff0c;docx文件。 最近需要处理一些爬虫得到的数据来进行一些自动化报告的操作&#xff0c;因为需要生成的是word的报告&#xff0c;所以估选用docxtpl库来直接生成模板 docxt…...

C++学习笔记总结练习:多态与虚函数

1 多态 多态分类 静态多态&#xff0c;是只在编译期间确定的多态。静态多态在编译期间&#xff0c;根据函数参数的个数和类型推断出调用的函数。静态多态有两种实现的方式 重载。&#xff08;函数重载&#xff09;模板。 动态多态&#xff0c;是运行时多态。通过虚函数机制实…...

linux 批量更改指定后辍文件的可执行权限

要在Linux上批量更改指定后缀文件的可执行权限&#xff0c;您可以使用find命令来查找这些文件&#xff0c;然后使用chmod命令来更改它们的权限。以下是一些步骤&#xff1a; 1. 打开终端。 2. 使用 find 命令查找要更改权限的文件&#xff0c;例如&#xff0c;如果您想要更…...

数据结构(Java实现)-Map和Set

搜索树 概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值 若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值 它的左右子树也…...

C++进程、线程、内存管理

目录 进程和线程区别 进程和线程切换的区别 系统调用流程 系统调用是否会引起线程切换 为什么需要使用虚拟内存 进程和线程区别 本质区别&#xff1a; 进程是资源分配的基本单元。 线程是操作系统调度的基本单元。 地址空间&#xff1a; 进程具有独立的虚拟地址空间。 线程…...

打车系统网约车系统开发支持APP公众号H5小程序版本源码

一、操作流程 二、业务模式 三、用户端 用户注册登录&#xff1a;未注册的手机号将自动创建账号 通过好友的邀请链接进行注册&#xff0c;将会绑定上下级关系 也可以注册的时候输入好友的邀请码&#xff0c;也可以绑定关系 用户充值&#xff1a; 用户下单支付时&#xff0c;可以…...

HTTP/1.1协议的状态码

2023年8月30日&#xff0c;周三下午 HTTP/1.1协议定义了一组状态码&#xff0c;用于表示请求的处理结果。 每个状态码都有特定的含义&#xff0c;它们以三位数字的形式出现在响应的状态行中。 下面是一些常见的HTTP/1.1协议的状态码及其含义&#xff1a; 1xx&#xff08;信息…...

SpringCloud(十)——ElasticSearch简单了解(一)初识ElasticSearch和RestClient

文章目录 1. 初始ElasticSearch1.1 ElasticSearch介绍1.2 安装并运行ElasticSearch1.3 运行kibana1.4 安装IK分词器 2. 操作索引库和文档2.1 mapping属性2.2 创建索引库2.3 对索引库的查、删、改2.4 操作文档 3. RestClient3.1 初始化RestClient3.2 操作索引库3.3 操作文档 1. …...

CAD文字显示?问号解决

背景 从别人哪儿发过来的CAD文件&#xff0c;打开后发现有些文字显示为&#xff1f; 问题排查 通过点击文字特性得知 该文字的样式是 SF和仿宋通过命令行执行st 得知&#xff0c;两种样式关联的字体都是仿宋GB_2312&#xff0c;但当前操作系统无此字体&#xff0c;故显示为&…...

Calico切换网络模式无效

Calico切换网络模式无效 Calico由原先的BGP模式切换为IP IP模式发现未生效&#xff0c;使用的模式还是BGP模式&#xff0c;Calico卸载后查询Etcd发现存在很多Calico数据 [rootk8s-master-1 ~]# etcdctl get / --prefix --keys-only | grep calico /calico/ipam/v2/assignment…...

数据生成 | MATLAB实现GAN生成对抗网络结合SVM支持向量机的数据生成

数据生成 | MATLAB实现GAN生成对抗网络结合SVM支持向量机的数据生成 目录 数据生成 | MATLAB实现GAN生成对抗网络结合SVM支持向量机的数据生成生成效果基本描述程序设计参考资料 生成效果 基本描述 数据生成 | MATLAB实现GAN生成对抗网络结合SVM支持向量机的数据生成。 生成对抗…...

iOS - 资源按需加载 - ODR

一、瘦身技术大图 二、On-Demand Resources 简介 将其保存管理在苹果的服务器&#xff0c;按需使用资源、优化包体积&#xff0c;实现更小的应用程序。ODR 的好处&#xff1a; 应用体积更小&#xff0c;下载更快&#xff0c;提升初次启动速度资源会在后台下载操作系统将会在磁…...

arduino仿真 SimulIDE1.0仿真器

SimulIDE 是一个开源的电子电路模拟器&#xff0c;支持模拟各种电子元器件的行为&#xff0c;可以帮助电子工程师和爱好者进行电路设计和测试。以下是 SimulIDE 的安装和使用说明&#xff1a; 安装 SimulIDE SimulIDE 可以在 Windows、Linux 和 Mac OS X 等操作系统上安装。您…...

vue实现导出excel的多种方式

在Vue中实现导出Excel有多种方式&#xff0c;可以通过前端实现&#xff0c;也可以通过前后端配合实现。下面将详细介绍几种常用的实现方式。 1. 前端实现方式&#xff1a; 使用xlsx库&#xff1a;使用xlsx库可以在前端将数据导出为Excel文件。首先需要安装xlsx库&#xff0c;…...

redis实战-实现优惠券秒杀解决超卖问题

全局唯一ID 唯一ID的必要性 每个店铺都可以发布优惠券&#xff1a; 当用户抢购时&#xff0c;就会生成订单并保存到tb_voucher_order这张表中&#xff0c;而订单表如果使用数据库自增ID就存在一些问题&#xff1a; id的规律性太明显&#xff0c;容易被用户根据id的间隔来猜测…...

C语言:截断+整型提升+算数转换练习

详情关于整型提升、算数转换与截断见文章&#xff1a; 《C语言&#xff1a;整型提升》 《C语言&#xff1a;算数转换》 一、代码一 int main() { char a -1; signed char b -1; unsigned char c -1; printf("%d %d %d", a, b, c); return 0; } 求…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

高分辨率图像合成归一化流扩展

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 1 摘要 我们提出了STARFlow&#xff0c;一种基于归一化流的可扩展生成模型&#xff0c;它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流&#xff08;TARFlow&am…...

echarts使用graphic强行给图增加一个边框(边框根据自己的图形大小设置)- 适用于无法使用dom的样式

pdf-lib https://blog.csdn.net/Shi_haoliu/article/details/148157624?spm1001.2014.3001.5501 为了完成在pdf中导出echarts图&#xff0c;如果边框加在dom上面&#xff0c;pdf-lib导出svg的时候并不会导出边框&#xff0c;所以只能在echarts图上面加边框 grid的边框是在图里…...

李沐--动手学深度学习--GRU

1.GRU从零开始实现 #9.1.2GRU从零开始实现 import torch from torch import nn from d2l import torch as d2l#首先读取 8.5节中使用的时间机器数据集 batch_size,num_steps 32,35 train_iter,vocab d2l.load_data_time_machine(batch_size,num_steps) #初始化模型参数 def …...