Java 中 AQS 的实现原理

news2025/7/19 16:53:11

AQS 简介

AQS(全称AbstractQueuedSynchronizer)即抽象同步队列,它是实现同步器的基础组件,并发包中锁的底层就是使用AQS实现的。

在这里插入图片描述

由类图可以看到,AQS是一个FIFO的双向队列,其内部通过节点head和tail记录队首和队尾元素,队列元素的类型为Node。

  • 其中Node中的thread变量用来存放进入AQS队列里面的线程。

    • prev记录当前节点的前驱节点

    • next记录当前节点的后继节点

  • Node节点内部的SHARED用来标记该线程是获取共享资源时被阻塞挂起后放入AQS队列的。

  • EXCLUSIVE用来标记线程是获取独占资源时被挂起后放入AQS队列的。

  • waitStatus记录当前线程等待状态,可以为CANCELLED(线程被取消了)、SIGNAL(线程需要被唤醒)、CONDITION(线程在条件队列里面等待)、PROPAGATE(释放共享资源时需要通知其他节点)。

在AQS中维持了一个单一的状态信息state,可以通过getState、setState、compareAndSetState函数修改其值。对于ReentrantLock的实现来说,state可以用来表示当前线程获取锁的可重入次数。

AQS 实现原理

AQS 依赖内部的同步队列实现,也就是FIFO双向队列,负责管理着线程同步时所有被阻塞的线程。

AQS队列内部维护的是一个双向链表,这种结构每个数据都有两个指针,分别指向当前节点的前驱节点和后继节点。当线程抢占锁失败的时候,会把当前线程封装成Node加入到AQS中去。

场景一:线程抢占锁失败时,AQS 的变化

1.AQS 的 head,tail分别是同步队列的头节点和尾节点,默认为 null。
在这里插入图片描述

2.当第一个线程抢夺锁失败,同步队列会先初始化,随后线程会被封装成Node节点追加到AQS队列中。假设当前独占锁的线程为ThreadA,抢占锁失败的线程为ThreadB。

  • 同步队列初始化,首先会在队列中添加一个空Node,这个节点中的thread=null,代表当前获取锁成功的线程。随后,AQS的head和tail会同时指向这个节点。
    在这里插入图片描述
  • 接下来将ThreadB封装成Node节点,追加到AQS队列。设置新节点的prev指向AQS队尾节点;将队尾节点的next指向新节点;最后将AQS尾节点指针指向新节点。此时AQS变化,如下图:
    在这里插入图片描述

3.当下一个线程抢夺锁失败时,重复上面步骤。将线程封装成Node,追加到AQS队列。假设此次抢占锁失败的线程为ThreadC,此时AQS变化,如下图:
在这里插入图片描述

线程被唤醒时,AQS 队列的变化

ReentrantLock 唤醒阻塞线程时,会按照FIFO的原则从AQShead头部开始唤醒首个节点中线程。

head节点表示当前获取锁成功的线程ThreadA节点。

当ThreadA释放锁时,它会唤醒后继节点线程ThreadB,ThreadB开始尝试获得锁,如果ThreadB获得锁成功,会将自己设置为AQS的头节点。ThreadB获取锁成功后,AQS变化如下:

  1. head指针指向ThreadB节点。

  2. 将原来头节点的next指向Null,从AQS中删除。

  3. 将ThreadB节点的prev指向Null,设置节点的thread=null。
    在这里插入图片描述
    上面就是线程在竞争锁时,线程被阻塞和被唤醒时AQS 队列的基本实现过程。

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

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

相关文章

『Python学习笔记』ubuntu解决matplotlit中文乱码的问题!

ubuntu解决matplotlit中文乱码的问题! 文章目录 simhei.ttf字体下载链接:http://xiazaiziti.com/210356.html将字体放到合适的地方 sudo cp SimHei.ttf /usr/share/fonts/(base) zkfzkf:~$ fc-list | grep -i "SimHei" /usr/local/share/font…

鸿蒙知识总结

判断题 1、 在http模块中,多个请求可以使用同一个httpRequest对象,httpRequest对象可以复用。(错误) 2、订阅dataReceiverProgress响应事件是用来接收HTTP流式响应数据。(错误) 3、ArkTS中变量声明时不需要…

C++23 新特性:深入解析 std::views::join_with(P2441R2)

文章目录 std::views::join_with 基本用法处理字符串集合std::views::join_with 与其他视图的结合使用总结 随着C23标准的逐步推进,我们迎来了许多令人兴奋的新特性,其中之一就是 std::views::join_with。这个新特性是C23中引入的视图适配器&#xff0c…

数据可视化大屏——智慧社区内网比对平台

综述分析: 智慧社区内网数据比对信息系统 这段代码实现了一个智慧社区内网数据比对信息系统的前端界面,采用三栏式布局展示各类社区安全相关数据。界面主要由左侧数据统计、中间地图展示和右侧数据分析三部分组成,使用了多种图表可视化技术…

Jenkins企业级实战

目标 在Windows操作系统上使用Jenkins完成代码的自动拉取、编译、打包、发布工作。 实施 1.安装Java开发工具包(JDK) Jenkins是基于Java的应用程序,因此需要先安装JDK。可以从Oracle官网或OpenJDK下载适合的JDK版本。推荐java17版本&#x…

uniapp-商城-52-后台 商家信息(商家信息数据,云对象使用)

1、概述 已经通过好几个篇幅来说明商家信息,包括logo、商家名称,地址,电话以及商家简介。通过表单组件和标签,以及我们的文件上传标签,都做了说明。(logo上传,用的文件上传组件是上传到公共的数…

MySQL 索引设计宝典:原理、原则与实战案例深度解析

目录 前言第一章:索引设计的基础原则 (知其然,更要知其所以然)第二章:实战案例:电商订单系统的索引设计第三章:索引设计的实践流程总结结语 🌟我的其他文章也讲解的比较有趣😁,如果喜…

C#上传文件到腾讯云的COS

测试环境: vs2022 .net 6控制台应用程序 测试步骤如下: 1 添加子用户,目前是为了拿到secretId和secretKey,打开添加子用户界面链接:https://console.cloud.tencent.com/cam 并为子用户添加API 密钥 2 通过链接htt…

C PRIMER PLUS——第9节:动态内存分配、存储类别、链接和内存管理

目录 1.动态内存分配 1.1 malloc 函数 1.2 calloc 函数 1.3 realloc 函数 1.4 free 函数 1.5常见错误 1.6综合例题 2.C语言的内存结构 3.存储类别 3.1作用域(Scope) 3.2链接(Linkage) 3.3存储期(Storage Du…

作业...

基础配置 RI R2 R3 R4 R5 例如R1 BGP配置 1,R1和R2之间使用直连接口IP地址来建立EBGP对等体关系 2、R2、R3、R4之间配置OSPF协议,保证各设备之间的网络互通,且通过重发布的方式发布路由 查看R2、R3、R4的OSPF路由表: \ R2、R3、R4使用环…

IC ATE集成电路测试学习——电流测试的原理和方法

电流测试 我们可以通过电流来判断芯片的工作状态时,首先先了解下芯片的电流是如何产生的。 静态电流 理论上,CMOS结构的芯片静态时几乎不耗电 CMOS基本结构:Pmos Nmos 串联当逻辑电平稳定时: ➜ 要么Pmos导通,Nmo…

快速理解动态代理

什么是动态代理(Java核心技术卷1的解释) 动态代理是一种运行时生成代理对象的技术,其本质是通过字节码增强在不修改原始类代码的前提下,动态拦截并扩展目标对象的行为。它通过代理对象对原始方法的调用进行拦截,并在方法执行前后注入自定义逻…

AugmentCode 非常昂贵的新定价

AugmentCode 现在的价格比 Cursor 和 Windsurf 的总和还要贵。 AugmentCode 曾是我开发工作流程的常用工具。出乎意料的是,他们改变了定价结构,让开发者们震惊不已。 原来的30 美元月费已经增长为50 美元月费,这是一个67%的增长。 改变我看法的不仅仅是价格上涨,还有他…

前端面试2

1. 面试准备 1. 建立自己的知识体系 思维导图ProcessOn框架Vue elementUI自查 https://zh.javascript.info/ 借鉴 https://juejin.cn/post/6844904103504527374http://conardli.top/blog/article/https://github.com/mqyqingfeng/Bloghttp://47.98.159.95/my_blog/#html 2.技能…

大疆卓驭嵌入式面经及参考答案

FreeRTOS 有哪 5 种内存管理方式? heap_1.c:这种方式简单地在编译时分配一块固定大小的内存,在整个运行期间不会进行内存的动态分配和释放。它适用于那些对内存使用需求非常明确且固定,不需要动态分配内存的场景,优点是…

架构进阶:74页数据架构设计总体规划方案【附全文阅读】

本文讨论了数据资源规划在信息化战略规划中的重要性,详细阐述了数据资源规划的方法与过程,包括系统架构、业务能力模型、数据架构等。 文章指出,数据资源规划需要梳理企业级数据模型,明确数据分布和流向,建立统一的数据…

情书大全v3.0.1

《情书大全》是一款致力于情书写作的手机应用程序,内置了丰富的情书范本及定制化服务。用户无论是想要倾诉爱意、交流友情还是传递亲情,都能在这款应用中寻得合适的情书样本。用户还可以根据自己的需求对模板进行编辑和调整,轻松创作出感人至…

基于OpenCV的人脸识别:LBPH算法

文章目录 引言一、概述二、代码实现1. 代码整体结构2. 导入库解析3. 训练数据准备4. 标签系统5. 待识别图像加载6. LBPH识别器创建7. 模型训练8. 预测执行9. 结果输出 三、 LBPH算法原理解析四、关键点解析五、改进方向总结 引言 人脸识别是计算机视觉领域的一个重要应用&…

鸿蒙 使用动画 简单使用

鸿蒙 使用动画 简单使用 动画就两个,属性动画和转场动画 属性动画只是组件的属性发生变化,而转场动画是指对将要出现或消失的组件做动画,而文档的其他动画只是给这两个动画效果锦上添花罢了 这篇文章简单介绍这两个动画,其他的…

arcgis和ENVI中如何将数据输出为tif

一、arcgis中转换为tif 右键图层: Data -> Export Data, 按照图示进行选择,选择tiff格式导出即可,还可以选择其他类型的格式,比如envi。 二、 ENVI中转换为tif File -> Save As -> Save As (ENVI, NITF, TIFF, DTED) …