Java多线程篇(11)——BlockingQueue(优先级阻塞,延迟队列)

文章目录

  • 1、PriorityBlockingQueue
  • 2、DelayQueue

1、PriorityBlockingQueue

优先级阻塞队列就是在优先级队列的基础上增加队列排序的功能,将高优先级排在前面,所以优先级队列的元素需要实现Comparator接口
如果数据结构用数组去维护队列的话,要么在put有大量的后移操作,要么在take有大量的前移操作。
为避免这个问题优先级队列内部用二叉堆的数据结构去实现,这样无论是put还是take都不会有大量的移动操作。具体逻辑如下:
put:如果优先级比父节点高就上浮,依次类推,直至不能再上浮
take:直接拿走堆顶元素,然后再用最后一个元素顶上堆顶,再根据优先级下沉该元素

不懂二叉堆的,可以先去查阅一下二叉堆或者堆排序。
虽然二叉堆不是完全有序的,但可以保证堆顶元素的优先级肯定是最高的。

put

    public void put(E e) {offer(e); //优先级队列是无界的,所以不需要阻塞,直接调用offer}//入队public boolean offer(E e) {if (e == null)throw new NullPointerException();final ReentrantLock lock = this.lock;//加锁lock.lock();int n, cap;Object[] es;//扩容//先释放锁,开辟新数组(长度= size<64? size+2 : size*1.5。)//之后再重新加锁复制到新数组while ((n = size) >= (cap = (es = queue).length))tryGrow(es, cap);try {final Comparator<? super E> cmp;//如果没有传入比较器就用默认的if ((cmp = comparator) == null)//二叉堆节点上浮siftUpComparable(n, e, es);elsesiftUpUsingComparator(n, e, es, cmp);size = n + 1;//有元素了,不为空,notEmpty.signalnotEmpty.signal();} finally {//释放锁lock.unlock();}return true;}//上浮private static <T> void siftUpComparable(int k, T x, Object[] es) {Comparable<? super T> key = (Comparable<? super T>) x;//如果k=0,说明上浮到堆顶了while (k > 0) {//二叉堆父节点在数据的下标=(当前节点下标-1)/2int parent = (k - 1) >>> 1;Object e = es[parent];//不能再上浮了就breakif (key.compareTo((T) e) >= 0)break;//可以上浮,交换当前节点和父节点    es[k] = e;k = parent;}es[k] = key;}

take

    public E take() throws InterruptedException {final ReentrantLock lock = this.lock;//加锁lock.lockInterruptibly();E result;try {//dequeue出队一个元素while ( (result = dequeue()) == null)//队列为空,notEmpty.await 阻塞notEmpty.await();} finally {//释放锁lock.unlock();}return result;}//出队private E dequeue() {final Object[] es;final E result;//堆顶记入resultif ((result = (E) ((es = queue)[0])) != null) {final int n;//--size并将最后一个元素记入x后清空(赋值null)final E x = (E) es[(n = --size)];es[n] = null;if (n > 0) {final Comparator<? super E> cmp;//如果没有传入比较器就用默认的if ((cmp = comparator) == null)//二叉堆节点下沉siftDownComparable(0, x, es, n);elsesiftDownUsingComparator(0, x, es, n, cmp);}}//返回堆顶return result;}//下沉private static <T> void siftDownComparable(int k, T x, Object[] es, int n) {Comparable<? super T> key = (Comparable<? super T>)x;//假如这里是 (n-1)/2 就是(前面被清空的那个)最后一个元素x的父节点下标//但这里是 (n/2),意味着当最后一个元素x是左孩子节点的话half就是父节点下标,右孩子节点的话half就是父节点下标+1int half = n >>> 1;//k>=half说明下沉到底了while (k < half) {//n*2+1就是左孩子节点int child = (k << 1) + 1;Object c = es[child];//右孩子节点=左孩子节点+1int right = child + 1;//在两个孩子节点中取优先级比较高去跟下沉节点比较if (right < n &&((Comparable<? super T>) c).compareTo((T) es[right]) > 0)c = es[child = right];//如果不能再下沉了就breakif (key.compareTo((T) c) <= 0)break;//可以下沉,交换当前节点和被选中的孩子节点  es[k] = c;k = child;}//最后别忘了替换下沉堆顶的值为被清空的最后一个元素xes[k] = key;}

2、DelayQueue

延迟队列是在优先级队列的基础上实现的(优先级按延迟时间排序),其内部维护了一个优先级队列。

注:是优先级队列而不是优先级阻塞队列,这两者的区别在于有无阻塞。
为什么要用优先级队列不用优先级阻塞队列?
因为不适用。延迟队列的put不需要阻塞,而take则是需要自己实现一个根据延迟时间来阻塞的逻辑。

在这里插入图片描述
put

    public void put(E e) {offer(e); //因为不需要阻塞,所以直接调用offer即可}public boolean offer(E e) {final ReentrantLock lock = this.lock;//加锁lock.lock();try {//优先级队列 PriorityQueue.offer() 入队q.offer(e);//如果入队后是第一个元素,需要更新leader的阻塞时间if (q.peek() == e) {//清空leader,leader记录带超时时间等待阻塞队列头节点的线程(只有一个)leader = null;//唤醒所有正在等待的线程重新take(自旋),以更新leader的阻塞时间,同时leader也可能会变available.signal();}return true;} finally {//释放锁lock.unlock();}}

take

    public E take() throws InterruptedException {final ReentrantLock lock = this.lock;//加锁lock.lockInterruptibly();try {for (;;) {//第一个节点E first = q.peek();//如果为空阻塞,available.await()if (first == null)available.await();else {//如果延迟时间到了,出队long delay = first.getDelay(NANOSECONDS);if (delay <= 0L)return q.poll();first = null;//下面的就是延迟时间还没到//如果已经有leader了,就不带超时时间的阻塞,后续由leader唤醒if (leader != null)available.await();//如果还没有leader,就记录leader是当前线程带并超时时间的阻塞else {//记录leader是当前线程Thread thisThread = Thread.currentThread();leader = thisThread;try {//带超时时间的阻塞available.awaitNanos(delay);} finally {//阻塞时间到了,清空leaderif (leader == thisThread)leader = null;}}}}} finally {//如果leader为空(leader的阻塞时间已到,此时leader已经获取到资源了)//且队列中还有资源//就唤醒后面等待的线程if (leader == null && q.peek() != null)available.signal();//释放锁lock.unlock();}}

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

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

相关文章

BUUCTF pwn1_sctf_2016 1

代码分析 查看文件信息然后进行反汇编 关键信息 32位栈不可执行 IDA反汇编 说实话&#xff0c;这个应该是C编写的程序&#xff0c;C基础还是不行&#xff0c;我硬是没看懂这个代码 我查了一下字符串 这里的get_flag是函数&#xff0c;另一个应该就是执行的一个命令了 到IDA…

C++算法:城市天际线问题

题目 城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度&#xff0c;请返回 由这些建筑物形成的 天际线 。 每个建筑物的几何信息由数组 buildings 表示&#xff0c;其中三元组 buildings[i] [lefti, righti, heighti] 表示&am…

Linux中怎么启动Zookeeper

首先进入Zookeeper安装目录下的bin目录 比如&#xff1a; cd /root/zookeeper-3.4.9/bin 然后在此目录下执行命令。 1. 启动Zookeeper Server端 ./zkServer.sh start 2.启动Zookeeper Client端 ./zkCli.sh 启动Zookeeper Client端后如下&#xff1a;

8年经验之谈 —— Web ui自动化测试框架总结!

实施过了web系统的UI自动化&#xff0c;回顾梳理下&#xff0c;想到什么写什么&#xff0c;随时补充。 首先&#xff0c;自动化测试不是手动测试的替代品&#xff0c;是比较好的补充&#xff0c;而且不是占大比重的补充。 70%的测试工作集中在底层接口测试和单元测试&#xff0…

CSS之排列系列--顶部导航栏ul、li居中展示的方法

原文网址&#xff1a;CSS之排列系列--顶部导航栏ul、li居中展示的方法_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍CSS顶部导航栏ul、li居中展示的方法。 核心方法 ul的父层使用&#xff1a;text-align: center ul元素使用&#xff1a;display: inline-block; 示例 …

外卖跑腿系统的关键功能和技术要点

1. 用户注册和登录 首先&#xff0c;用户需要能够注册新账户并登录。以下是使用Python和Django框架的代码示例&#xff0c;展示如何创建用户注册和登录功能。 # Django视图代码 from django.contrib.auth import login, authenticate from django.contrib.auth.forms import…

10.12按键中断

设置按键中断&#xff0c;按键1按下&#xff0c;LED亮&#xff0c;再按一次&#xff0c;灭 按键2按下&#xff0c;蜂鸣器响。再按一次&#xff0c;不响 按键3按下&#xff0c;风扇转&#xff0c;再按一次&#xff0c;风扇停 keyit.h: #ifndef __KEYIT_H__ #define __KEYIT_…

选实验室超声波清洗机易忽视的内容?小型清洗机的优点有?

实验室超声波清洗机如今在行业内占据着重要的一席之地&#xff0c;摒弃了传统模式&#xff0c;坚持以超声波为主的清洗方式&#xff0c;在市场中获得的反响强烈。服务好&#xff0c;有诚信的实验室超声波清洗机能够消除客户的后顾之忧&#xff0c;工作人员会以真诚态度向客户提…

ubuntu|23 安装Gnome主题

ubuntu23 安装主题 进入网站选择需要的主题 https://www.opendesktop.org/s/Gnome/p/1357889 1 资源下载 经常加载不出来&#xff0c; 这里直接进入github下载源码 下载zip 2 安装主题 根据文档提示&#xff0c; 执行install.sh就能安装 3 切换主题 安装 tweak工具 sudo …

sql server判断两个集合字符串是否存在交集

sql server判断字符串A101;A102和字符串A102;A103是否存在交集 我们编写两个函数&#xff1a; 1&#xff09;函数fn_split将字符串拆分成集合 create function [dbo].[fn_split](inputstr varchar(8000), seprator varchar(10)) returns temp table (Result varchar(200)) a…

【Python学习笔记】类型/运算/变量/注释

前言 人生苦短&#xff0c;追求生产力&#xff0c;做一只时代风口的猪&#xff0c;应该学python Python语言中&#xff0c;所有的数据都被称之为对象。 1. 对象类型 Python语言中&#xff0c;常用的数据类型有&#xff1a; 整数&#xff0c; 比如 3 小数&#xff08;也叫浮…

qt中json类

目录 QJsonValue QJsonObject QJsonArray QJsonDocument 案例&#xff1a; Qt 5.0开始提供了对Json的支持&#xff0c;我们可以直接使用Qt提供的Json类进行数据的组织和解析&#xff0c;下面介绍4个常用的类。 QJsonValue 该类封装了JSON支持的数据类型。 布尔类型&#xf…

云原生Kubernetes:K8S集群版本升级(v1.20.15 - v1.22.14)

目录 一、理论 1.K8S集群升级 2.集群概况 3.升级集群&#xff08;v1.21.14&#xff09; 4.验证集群&#xff08;v1.21.14&#xff09; 5.升级集群&#xff08;v1.22.14&#xff09; 6.验证集群 (v1.22.14) 二、实验 1.升级集群&#xff08;v1.21.14&#xff09; 2.验…

Text-to-SQL小白入门(八)RLAIF论文:AI代替人类反馈的强化学习

学习RLAIF论文前&#xff0c;可以先学习一下基于人类反馈的强化学习RLHF&#xff0c;相关的微调方法&#xff08;比如强化学习系列RLHF、RRHF、RLTF、RRTF&#xff09;的论文、数据集、代码等汇总都可以参考GitHub项目&#xff1a;GitHub - eosphoros-ai/Awesome-Text2SQL: Cur…

软件测试之概念篇(需求,测试用例,BUG描述,产品的生命周期)

目录 1.什么是需求 2.什么是测试用例 3.什么是BUG 4.软件的生命周期 5.测试的生命周期 1.什么是需求 在大多数软件公司&#xff0c;一般会有两部分需求&#xff1a; 用户需求&#xff1a;可以理解为就是甲方提出需求&#xff0c;如果没有甲方&#xff0c;那么就是终端用…

Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0

今天打包springboot项目的时候报错&#xff1a; Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0 最后通过如下方法解决&#xff1a; 在pom.xml中加入如下依赖&#xff1a; <plugin><groupId>org.apache.maven.plugins</groupI…

推荐一个拥有386万订阅者,10000多免费学习视频的频道

自从开始搞YouTube中文配音以来&#xff0c;我们一直是7*24小时&#xff0c;夜以继日的在批量处理一些优质的学习资源&#xff0c;一方面是翻译&#xff0c;另一方面是配音。这样用户在打开的时候&#xff0c;就能获得经过我们优化的翻译和配音了。 这次我们刚刚处理完一个油管…

面试题补充

1.公司有几套环境&#xff1a;测试环境&#xff08;测试人员使用&#xff09;&#xff0c;开发环境&#xff08;开发人员使用&#xff09;&#xff0c;预生产环境&#xff08;测试人员使用&#xff09;&#xff0c;生产环境&#xff08;用户使用&#xff09; 2.作为一名测试&a…

Godot 单元测试

前言 单元测试是我们常用的功能&#xff0c;Godot作为一个游戏&#xff0c;单元测试和热重载是我们常用的功能。这里我们讲解最简单的单元测试的情况。 Godot 配置 我们添加一个最简单的节点&#xff0c;挂载一个最简单的脚本。 添加测试方法&#xff08;只能是静态方法&…

STM32 多功能按键中断

key1 开关实现led1亮灭,key2开关实现蜂鸣器开关,key3开关实现风扇开关 main.c #include "uart.h" #include "key_it.h" #include "led.h" int main() {char c;char *s;uart4_init();//串口初始化all_led_init();key_it_config();fengshan_init…