AQS底层源码深度剖析-BlockingQueue

news2025/8/7 17:01:28

目录

AQS底层源码深度剖析-BlockingQueue

BlockingQueue定义

队列类型

队列数据结构

ArrayBlockingQueue

LinkedBlockingQueue

DelayQueue

BlockingQueue API

添加元素

检索(取出)元素

BlockingQueue应用队列总览图

AQS底层源码深度剖析-BlockingQueue【重点中的重点】

看源码前,先要明白Condition的含义:

BlockingQueue源码会涉及三个队列【重点掌握】:

put()源码剖析:

 take()源码剖析:

 总结:


AQS底层源码深度剖析-BlockingQueue

BlockingQueue定义

线程通信一个工具,在任意时刻,不管并发有多高,在单台JVM上,同一时间永远只能有一个线程能够对队列进行入队或者出队操作。

官方点说:BlockingQueue,是java.util.concurrent包提供的用于解决并发生产者-消费者问题的最有用的类,它的特性是在任意时刻只有一个线程可以进行take或put操作,并且BlockingQueue提供了超时return null的机制,在许多生产应用场景里都可以看到这个工具的身影。

应用场景:

线程池,springcloud-Eureka的三级缓存,Nacos,Netty,MQ

队列类型

  1. 无限队列 (unbounded queue ) - 几乎可以无限增长
  2. 有限队列 ( bounded queue ) - 定义了最大容量

队列数据结构

队列实质就是一种存储数据的结构

  • 通常用链表或者数组实现
  • 一般而言队列具备FIFO先进先出的特性,当然也有双端队列(Deque)优先级队列
  • 主要操作:入队(EnQueue)与出队(Dequeue)

常见的4种阻塞队列

  • ArrayBlockingQueue 由数组支持的有界队列
  • LinkedBlockingQueue 由链接节点支持的可选有界队列
  • PriorityBlockingQueue 由优先级堆支持的无界优先级队列
  • DelayQueue 由优先级堆支持的、基于时间的调度队列

ArrayBlockingQueue

队列基于数组实现,容量大小在创建ArrayBlockingQueue对象时已定义好

数据结构如下图:

 队列创建:

BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>();

应用场景

在线程池中有比较多的应用,生产者消费者场景

工作原理

基于ReentrantLock保证线程安全,根据Condition实现队列满时的阻塞

LinkedBlockingQueue

是一个基于链表的无界队列(理论上有界)

BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();

上面这段代码中,blockingQueue的容量将设置为Integer.MAX_VALUE

向无限容量的队列中添加元素的所有操作都将永远不会阻塞,因此它可以增长到非常大的容量(注意 这里不是说不会加锁保证线程安全,同样会加锁来保证同一时刻只会有一个线程对队列添加元素或取出元素成功)

使用无限容量的BlockingQueue设计生产者-消费者模型时最重要的是消费者应该能够像生产者向队列添加消息一样快的消费消息。否则存储消息数据的内存可能会填满,然后得到一个OutOfMemory异常

DelayQueue

由优先级堆支持的、基于时间的调度队列,内部基于无界队列PriorityQueue实现,而无界队列基于数组的扩容实现。

队列创建:

BlockingQueue<String> blockingQueue = new DelayQueue();

要求:

入队的对象必须要实现Delayed接口,而Delayed集成自Comparable接口

应用场景:

电影票

工作原理:

队列内部会根据时间优先级进行排序。延迟类线程池周期执行。

BlockingQueue API

BlockingQueue 接口的所有方法可以分为两大类:负责向队列添加元素的方法和检索(取出)这些元素的方法。在队列满/空的情况下,来自这两个组的每个方法的行为都不同。

添加元素

方法

说明

add()

如果插入成功则返回 true,否则抛出 IllegalStateException 异常

put()

将指定的元素插入队列,如果队列满了,那么会阻塞直到有空间插入

offer()

如果插入成功则返回 true,否则返回 false

offer(E e, long timeout, TimeUnit unit)

尝试将元素插入队列,如果队列已满,那么会阻塞直到有空间插入

检索(取出)元素

方法

说明

take()

获取队列的头部元素并将其删除,如果队列为空,则阻塞并等待元素变为可用

poll(long timeout, TimeUnit unit)

检索并删除队列的头部,如有必要,等待指定的等待时间以使元素可用,如果超时,则返回 null

在构建生产者 - 消费者程序时,这些方法是 BlockingQueue 接口中最重要的构建块。

BlockingQueue应用队列总览图

应用队列:存储消息数据的队列。无论是consumer还是producer,想要对应用队列中的消息数据进行操作(存入或取出)时,必须先获取到锁对象。如果获取不到锁,则无法操作。

(1) 

极端情况下:

当producer把队列容量放满了,那么producer释放锁,producer阻塞,让consumer获取到锁 然后去消费消息数据

同理当consumer消费完队列中的消息数据,那么consumer会释放锁,consumer阻塞,让producer获取到锁,然后去生产并且加入消息数据到队列中

普通情况下:

当然应用队列中没有放满,consumer也可以消费取出数据 。队列数据没有被消费完时,producer也可以生产消息并且存入应用队列中。

(2) 当producer在同步队列中存入一个消息数据后,会进行通知consumer,consumer接收到通知,会从条件队列中转移到阻塞CLH队列,在CLH阻塞队列中的consumer会进行消费应用队列中存储的消息数据

 AQS底层源码深度剖析-BlockingQueue【重点中的重点】

以下会深度剖析BlockingQueue的put()和take()方法的底层实现源码,一步步走完后会进行总结。如果不看源码,就没有任何的说服性。

看源码前,先要明白Condition的含义:

Condition的实现ConditionObject:

ConditionObject是AQS类的内部类,在BlockingQueue底层的实现中主要功能有:等待队列,等待和通知。

等待队列,等待和通知:源码中会使用到notEmpty和notFull

notEmpty: 消费者对应的等待队列。有啥用?当应用队列中的数据被消费完毕后,最后一次消费数据的消费者会释放掉自己持有的锁,然后调用notEmpty.await()加入到notEmpty等待队列的尾部。并且会调用notFull.signal()表示唤醒生产者等待队列中的一个节点加入到CLH阻塞队列中去[因为队列中没有数据啦,所以要唤醒生产者加入到CLH阻塞队列中]。

notFull:生产者对应的等待队列。有啥用?当应用队列中的空间已经被数据占满后,最后一次生产数据的生产者会释放掉自己持有的锁,然后调用notFull.await()加入到notFull等待队列的尾部。并且会调用notEmpty.signal()表示唤醒消费者等待队列中的一个节点加入到CLH阻塞队列中去[因为队列的空间被数据占满啦,所以要唤醒消费者加入到CLH阻塞队列中]。

补充:

其实唤醒也不是说只有当极端情况下(队列被占满或队列为空)才会进行唤醒消费者或生产者,其实每一次往队列中进行加入或取出数据都会导致各自的唤醒操作。

eg:加入一条数据会导致唤醒一个消费者等待队列中的消费者加入到CLH队列。取出一条数据时同理即可。

BlockingQueue源码会涉及三个队列【重点掌握】:

1.应用队列:

存放消息数据,模拟出的一个虚拟队列概念,可以认为是一个虚拟的不存在的存储结构,底层是使用数组进行存储插入应用队列的数据,以此模拟出一个应用队列。

2.CLH双端阻塞队列:存储封装当前线程对象对应的Node节点,是底层真实存在的一个队列

3.条件等待队列:这个就是上面Condition中记录的:notEmpty和notFull

put()源码剖析:

API层面调用put()方法其实就是生产者加入一条数据到应用队列

1.

 2.

3.put方法解析

生产者插入一个数据到应用队列,以下为具体的分析过程:

对put()方法中的await()方法解析一下:

对put方法中的equeue()方法解析:

 take()源码剖析:

 API层面调用take()方法其实就是生产者从应用队列中取出一条数据

1.

2.

3.

 对take()中的await方法解析: 

 对take()中的dequeue方法解析:

 总结:

(1)记清楚三个队列

(2)明白Condition的含义

(3)画出图即可

其实也没啥,看懂了也挺简单的,关于这个源码的图,使用processon绘制:

 ProcessOn Flowchart

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

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

相关文章

Spark Join大大表

Spark Join大大表分而治之拆分内表外表的重复扫描案例负隅顽抗数据分布均匀数据倾斜Task 数据倾斜Executor 数据倾斜两阶段 ShuffleExecutors 调优案例Join 大大表 : Join 的两张体量较大的事实表&#xff0c;尺寸相差在 3 倍内&#xff0c;且无法广播变量用大表 Join 大表才能…

观点丨Fortinet谈ChatGPT火爆引发的网络安全行业剧变

FortiGuard报告安全趋势明确指出“网络攻击者已经开始尝试AI手段”&#xff0c;ChatGPT的火爆之际的猜测、探索和事实正在成为这一论断的佐证。攻守之道在AI元素的加持下也在悄然发生剧变。Fortinet认为在攻击者利用ChatGPT等AI手段进行攻击的无数可能性的本质&#xff0c;其实…

动环监控4大应用价值,这个价值最大

机房管理&#xff0c;已成为企业管理和发展的首要任务。为提升机房管理的效率&#xff0c;应从空间环境、设备性能等多角度&#xff0c;对机房环境监测进行实时监控掌握相关数据参数&#xff0c;确保故障隐患及时发现&#xff0c;提高机房整体管理水平&#xff0c;降低运维难度…

Hadoop三大框架之HDFS

一、概述HDFS产生的背景及定义HDFS产生背景随着数据量越来越大&#xff0c;在一个操作系统存不下所有的数据&#xff0c;那么就分配到更多的操作系统管理的磁盘中&#xff0c;但是不方便管理和维护&#xff0c;需要一种系统来管理多台机器上的文件&#xff0c;这就是分布式文件…

一篇文章带你了解折线图

在我们的日常生活中&#xff0c;折线图随处可见&#xff0c;如医院里的心电图、股市里的股票走势、企业中的财务报表分析&#xff0c;但是折线图的具体适用情形&#xff0c;你真的了解吗&#xff1f; 折线图&#xff08;line chart&#xff09;也叫曲线图&#xff0c;用于显示数…

javaWeb在线考试系统

一、项目简介 本项目是一套javaWeb在线考试系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse 确保…

python-pandapower电力系统状态估计(算例1:讲解以及基本算例实现)

提示:专栏解锁后可以查看该专栏所有文章划算 全文截图如下 文章目录 前言一、状态估计1 理论背景2 测量量3 标准偏差二、工具箱函数讲解1 定义测量create_measurement()2 运行状态估计estimate( )3 不良数据处理remove_bad_data();chi2_analysis()remove_bad_data()…

k8s调度之初探nodeSelector和nodeAffinity

在k8s的调度中&#xff0c;有强制性的nodeSelector&#xff0c;节点亲和性nodeAffinity、Pod亲和性podAffinity、pod反亲和性podAntiAffinity。本篇先对nodeSelector和nodeAffinity做个初探。进入主题之前&#xff0c;先看看创建pod的大概过程kubectl向apiserver发起创建pod请求…

【UE4 RTS游戏】01-项目准备

步骤新建一个工程&#xff0c;选择俯视角游戏模板我命名工程如下&#xff1a;删除场景内的所有cube再删除Floor和Wall删除TopDownCharacter删除“NavgationMeshBoundVolume”删除“TamplateLabel”和“RecastNavMesh-Default”删除LightmassImportanceVolume、PostProcessVolum…

【java】java异常分类和异常处理以及面试中常见的问题

文章目录什么是异常&#xff1f;程序错误一般分为三种编译错误运行时错误逻辑错误两个子类区别java几种常见的异常&#xff1a;运行时异常&#xff1a;IOException异常的产生&#xff1a;异常的处理&#xff1a;消极的处理&#xff1a;积极的处理&#xff1a;(异常捕获)throw和…

Jenkins自动化部署入门

Jenkins自动化部署入门 一、简介 Jenkins是一个开源软件项目&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件的持续集成变成可能。 Jenkins自动化部署实现原理 二、Jenkins部…

交互:可以执行命令行的框架才是好框架

上一节课&#xff0c;我们开始把框架向工业级迭代&#xff0c;重新规划了目录&#xff0c;这一节课将对框架做更大的改动&#xff0c;让框架支持命令行工具。 第三方命令行工具库 cobra obra 不仅仅能让我们快速构建一个命令行&#xff0c;它更大的优势是能更快地组织起有许多…

SpringBoot整合Mybatis详解

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、创建项目&#xff0c;导入依赖&#xff0c;完善项目结构二、编码1.yml配置2.编写实体类3.编写mapper.xml和接口4.编写业务层5.编写控制层6.启动类加上包扫描…

实践分享:Vue 项目如何迁移小程序

最近我们小组刚经历了将成熟的 HTML5 项目转换成小程序&#xff0c;并在app中运行的操作&#xff01;记录下来分享给各位。 项目&#xff1a;将已有的 Vue 项目转为小程序&#xff0c; 在集成了FinClip SDK 的 App 中运行。 技术&#xff1a;uni-app、FinClip 两个注意事项&…

多机器人集群网络通信协议分析

本文讨论的是多机器人网络通信各层的情况和协议。 每个机器人连接一个数据传输通信模块&#xff08;以下简称为数传&#xff0c;也泛指市面上的图传或图数一体的通信模块&#xff09;&#xff0c;数传之间进行组网来传递信息。 根据ISO的划分&#xff0c;网络通信的OSI模型分…

速看|快速软件开发框架突破信息孤岛,高效实现数字化发展!

在企业办公自动化发展的过程中&#xff0c;各部门之间的信息链接存在着链接不及时、信息孤岛的现象。伴随着日益激烈的市场竞争&#xff0c;这样单枪匹马的作战方式已经让不少企业吃尽了苦头&#xff0c;借助快速软件开发框架&#xff0c;可以有效打破信息孤岛&#xff0c;让各…

Jetpack Compose 中适配不同的屏幕尺寸

窗口大小分类 Compose 将 Android 设备的屏幕尺寸分为三类&#xff1a; Compact: 小屏幕&#xff0c;一般就是手机设备&#xff0c;屏幕宽度 < 600dpMedium&#xff1a;中等屏幕&#xff0c;大号的板砖手机如折叠屏或平板的竖屏&#xff0c;600dp < 屏幕宽度 < 840d…

swagger关闭/v2/api-docs仍然可以访问漏洞

今天接到安全团队的说swagger有未授权访问漏洞&#xff0c;即使在swagger关闭的情况下http://127.0.0.1:8086/agcloud/v2/api-docs?group%E7%94%A8%E6%88%B7%E5%85%B3%E8%81%94%E4%BF%A1%E6%81%AF%E6%A8%A1%E5%9D%97仍然还能访问。 看了下原来是有写一个拦截器 registry.addI…

图表控件TeeChart for .NET系列教程六:将数据添加到系列中(使用系列)

TeeChart for .NET是优秀的工业4.0 WinForm图表控件&#xff0c;官方独家授权汉化&#xff0c;集功能全面、性能稳定、价格实惠等优势于一体。TeeChart for .NET 中文版还可让您在使用和学习上没有任何语言障碍&#xff0c;至少可以节省30%的开发时间。 TeeChart for .NET最新…

BFD协议原理

BFD协议原理引入背景不使用BFD带来的问题OSPF感知慢VRRP产生次优路径BFD技术简介BFD会话建立方式和检测机制BFD会话建立过程BFD工作流程BFD的单臂回声BFD默认参数以及调整方法总结引入背景 随着网络应用的广泛部署&#xff0c;网络发生中断可能影响业务正常运行并造成重大损失…