【并发编程JUC】AQS详解
定义理解
AQS,全称为AbstractQueuedSynchronizer,是Java并发包(java.util.concurrent)中的一个框架级别的工具类,用于构建锁和同步器。它是许多同步类的基础,如ReentrantLock、Semaphore、CountDownLatch等,都是通过实现AQS的模板方法来实现其内部同步逻辑的。
- 同步状态:AQS使用一个volatile int类型的变量来表示同步状态,通过内置的FIFO(先进先出)队列(也称为CLH队列,一个虚拟的双向队列)来完成获取资源线程的排队工作。这个状态变量是线程共享的,用于表示同步资源的状态。
- CLH队列:CLH(Craig, Landin, and Hagersten)队列是AQS内部用于管理等待获取同步状态的线程的队列。它是一个虚拟的双向队列,即不存在队列实例,仅存在节点之间的关联关系。每个等待获取锁的线程都被封装成一个队列的节点(Node)。(将没有获取锁的线性封装成节点)

理解锁和同步器的关系
- 锁(Lock):锁是面向使用者的,它定义了使用者与锁交互的接口,比如允许两个线程并行访问某个资源,但隐藏了实现细节。锁是一个更高级的同步机制,它提供了比synchronized关键字更丰富的功能和灵活性。常见的锁实现有ReentrantLock等。
- 同步器(AbstractQueuedSynchronizer, AQS):同步器是面向锁的实现者的,它简化了锁的实现方式,屏蔽了同步状态管理、线程的排队、等待与唤醒等底层操作。同步器是构建锁和其他同步组件的基础框架,通过提供一套模板方法,使得开发者能够轻松地实现自定义的同步逻辑。
- 锁的实现依赖于同步器:在锁的实现中,通常会聚合同步器(AQS)来实现锁的语义。同步器为锁提供了必要的同步机制,如线程的排队、等待与唤醒等,从而简化了锁的实现复杂度。
AQS结构

梳理结构
- Lock是Java并发包(java.util.concurrent.locks)中的一个接口
- ReentrantLock是Lock接口的一个具体实现,它提供了可重入的互斥锁。
- Sync是ReentrantLock中的一个内部抽象类,它继承自AbstractQueuedSynchronizer(AQS)。
- FairSync是ReentrantLock中的一个内部类,它继承自Sync类。
- NonfairSync同样是ReentrantLock的一个内部类,也继承自Sync类
- AQS是Java并发包中的一个基础类,用于构建同步器(如锁和其他同步组件)。
Lock接口定义了锁的基本行为;ReentrantLock是Lock接口的一个具体实现,提供了可重入的互斥锁;Sync是ReentrantLock的内部抽象类,用于提供锁的基本实现机制;FairSync和NonfairSync是Sync的两个子类,分别实现了公平锁和非公平锁的逻辑;AQS则是ReentrantLock等同步器实现同步功能的基础。这些组件共同构成了Java并发包中强大的锁机制。
非公平锁源码如下:

公平锁源代码如下:


在非公平锁中,由于新到来的线程有可能直接尝试获取锁(而不需要排队),因此唤醒机制需要灵活处理。
模拟示例

假设有三个线程A、B、C都试图获取同一个ReentrantLock的锁(该锁以非公平模式配置)。

线程A的行为
- 尝试获取锁:线程A首先调用lock()方法,该方法内部会尝试通过compareAndSetState(0, 1)将锁的状态从0(未锁定)更改为1(锁定)。如果当前没有其他线程持有锁(即锁状态为0),则线程A成功获取锁。
- 执行业务逻辑:线程A在获取锁之后执行其业务逻辑。
线程B和C的行为(几乎同时)
当线程A持有锁时,线程B和C尝试获取锁。
- 调用acquire(1):线程B和C都调用acquire(1)方法,该方法是非公平锁获取锁的主要入口。
- 尝试非公平获取锁:acquire(1)内部调用tryAcquire(1),进而调用nonfairTryAcquire(1)。nonfairTryAcquire(1)首先检查当前锁状态是否为0(即未锁定),如果是,则尝试通过compareAndSetState(0, 1)获取锁。但由于线程A已经持有锁,所以B和C的这一步都会失败。(如果占用线程和当前线性为同一线程时,即为可重入锁)
- 添加等待者:由于nonfairTryAcquire(1)返回false,线程B和C都会调用addWaiter()方法将自己封装成一个节点(Node),并通过enq(node)方法将节点加入到等待队列中。如果队列为空(即还没有其他线程在等待),则初始化头节点(head)并设置尾节点(tail)为新加入的节点。否则,将新节点添加到队尾。
- 进入等待队列并等待:线程B和C在加入等待队列后,会调用acquireQueued(node, 1)方法。在这个方法中,线程会进入一个自旋循环,不断检查前驱节点的状态,并尝试通过park()方法使自己进入等待状态(阻塞)。如果前驱节点的状态是SIGNAL(-1),则线程会通过LockSupport.park(this)被阻塞,直到被唤醒。
线程A释放锁
- 释放锁:当线程A完成其业务逻辑后,会调用unlock()方法来释放锁。这会将锁的状态从1改回0,并唤醒等待队列中的一个线程(如果有的话)。
- 唤醒等待线程:在释放锁的过程中,unlock()方法会调用LockSupport.unpark(thread)来唤醒等待队列中的一个线程。由于是非公平锁,被唤醒的线程不一定是等待时间最长的线程(即队列的头部线程)。
线程B或C被唤醒
被唤醒的线程(可能是B也可能是C,这取决于线程调度器的决策)会重新进入acquireQueued(node, 1)方法的自旋循环,并再次尝试获取锁。如果此时锁已被释放(即状态为0),则该线程可能会成功获取锁并退出自旋循环,继续执行其业务逻辑。
相关文章:
【并发编程JUC】AQS详解
定义理解 AQS,全称为AbstractQueuedSynchronizer,是Java并发包(java.util.concurrent)中的一个框架级别的工具类,用于构建锁和同步器。它是许多同步类的基础,如ReentrantLock、Semaphore、CountDownLatch等…...
如何找BMS算法、BMS软件的实习
之前一直忙,好久没有更新了,今天就来写一篇文章来介绍如何找BMS方向的实习,以及需要具备哪些条件,我的实习经历都是在读研阶段找的,读研期间两段的实习经历再加上最高影响因子9.4分的论文,我的秋招可以说是…...
AR视频技术与EasyDSS流媒体视频管理平台:打造沉浸式视频体验
随着增强现实(AR)技术的飞速发展,其在各个领域的应用日益广泛。这项技术通过实时计算摄影机影像的位置及角度,将虚拟信息叠加到真实世界中,为用户带来超越现实的感官体验。AR视频技术不仅极大地丰富了我们的视觉体验&a…...
每天一个数据分析题(三百九十九)- 逻辑回归
逻辑回归中,若选0.5作为阈值区分正负样本,其决策平面是( ) A. wxb= 0 B. wxb= 1 C. wxb= -1 D. wxb= 2 数据分析认证考试介绍:点击进入 题目来源于CDA模拟题库 点…...
【ARMv8/v9 GIC 系列 5.2 -- GIC 分组介绍:Group 0 |Group 1| Non-Secure Group 1】
请阅读【ARM GICv3/v4 实战学习 】 文章目录 GIC Interrupt grouping中断分组配置寄存器GIC 中断分组介绍Group 0(安全组0)Group 1(安全组1)Non-Secure Group 1(非安全组1)总结及例子GIC Interrupt grouping ARM GICv3 通过中断分组机制,与ARMv8异常模型和安全模型进行…...
前端代码规范 - 日志打印规范
在前端开发中,随着项目迭代升级,日志打印逐渐风格不一,合理的日志输出是监控应用状态、调试代码和跟踪用户行为的重要手段。一个好的日志系统能够帮助开发者快速定位问题,提高开发效率。本文将介绍如何在前端项目中制定日志输出规…...
C# 类型转换之显式和隐式
文章目录 1、显式类型转换2. 隐式类型转换3. 示例4. 类型转换的注意事项5. 类型转换的应用示例总结 在C#编程中,类型转换是一个核心概念,它允许我们在程序中处理不同类型的数据。类型转换可以分为两大类:显式类型转换(Explicit Ca…...
Ubuntu多显示器设置不同缩放比例
Ubuntu多显示器设置不同缩放比例 设备问题解决方案 设备 笔记本屏幕分辨率为2560 \times 1600,外接显示器的分辨率为3840 \times 2160。 问题 Ubuntu默认的显示器设置中,缩放仅能选择100%,200%,300%,400%。假…...
以太网协议介绍——UDP
注:需要先了解一些以太网的背景知识,方便更好理解UDP协议、 以太网基础知识一 以太网基础知识二 UDP协议 UDP即用户数据报协议,是一种面向无连接的传输层协议,属于 TCP/IP 协议簇的一种。UDP具有消耗资源少、通信效率高等优点&a…...
FFMpeg rtmp 无压缩推送本地yuv文件 压缩推送本地yuv文件
可以借鉴的:C使用FFmpeg实现YUV数据编码转视频文件_C 语言_脚本之家 yuv文件下载地址:YUV Sequences 无压缩的方式推送本地yuv文件 代码: #include <stdio.h> #include <unistd.h> #include <iostream> extern "C&…...
PostgreSQL LIMIT 子句
PostgreSQL LIMIT 子句 PostgreSQL 是一种功能强大的开源对象关系数据库管理系统,广泛用于各种应用中。在处理大量数据时,我们通常只需要检索部分记录,而不是整个数据集。这时,LIMIT 子句就变得非常有用。本文将详细介绍 Postgre…...
误删分区后的数据拯救:双管齐下恢复策略
在数字化时代,数据的价值日益凸显,而误删分区作为常见的数据安全威胁之一,常常让用户措手不及。本文将深入探讨误删分区的现象,并为您揭示两种高效的数据恢复方案,旨在帮助您在最短时间内找回失去的数据,同…...
git 添加本地分支, clean
//以develop为源创建本地分支fromdevelop git checkout -b fromdevelop git add . git commit -m "local" git checkout -b local/dev //切换到远程分支. git checkout dev git clean_git clean -f -d-CSDN博客 git clean -f -d #删除当前目录下没有被track…...
Linux:进程间通信(一.初识进程间通信、匿名管道与命名管道、共享内存)
上次结束了基础IO:Linux:基础IO(三.软硬链接、动态库和静态库、动精态库的制作和加载) 文章目录 1.认识进程间通信2.管道2.1匿名管道2.2pipe()函数 —创建匿名管道2.3匿名管道的四种情况2.4管道的特征 3.基于管道的进程池设计4.命…...
QML-各类布局
Colunm布局 Column{id:colspacing: 30Repeater{id:repmodel: ListModel{}Button{width: 100height: 50text: "btn"index}}//开始时候移动move: Transition {NumberAnimation { properties: "x,y"; easing.type: Easing.OutBounce }}//添加时变化add:Transi…...
el-table封装点击列筛选行数据功能,支持筛选,搜索,排序功能
数据少的话,可以前端实现,如果多的话,建议还是请求接口比较合理父组件: <template> <div class"home"> <!-- <img alt"Vue logo" src"../assets/logo.png"> <HelloWorld …...
【SpringBoot3学习 | 第1篇】SpringBoot3介绍与配置文件
文章目录 前言 一. SpringBoot3介绍1.1 SpringBoot项目创建1. 创建Maven工程2. 添加依赖(springboot父工程依赖 , web启动器依赖)3. 编写启动引导类(springboot项目运行的入口)4. 编写处理器Controller5. 启动项目 1.2 项目理解1. 依赖不需要写版本原因2. 启动器(Starter)3. Sp…...
SpringBoot整合Dubbo的快速使用教程
目录 一、什么是Dubbo? 二、SpringBoot整合Dubbo 1、父工程引入依赖 2、各个Dubbo服务子模块引入依赖 3、服务提供者 (1)启动类添加注解EnableDubbo (2)服务类添加注解DubboService (3)配置文件…...
昇思25天学习打卡营第12天| 基于MindNLP+MusicGen生成自己的个性化音乐
之前都是看图文类的东西,今天体验一点不一样的。来点听力的内容。 mindspore有音乐生成模型MusicGen,MusicGen支持两种生成模式:贪心(greedy)和采样(sampling)。在实际执行过程中,采…...
代理设计模式和装饰器设计模式的区别
代理设计模式: 作用:为目标(原始对象)增加功能(额外功能,拓展功能) 三种经典应用场景: 1:给原始对象增加额外功能(spring添加事务,Mybatis通过代理实现缓存功能等等) 2:远程代理(网络通信,输出传输(RPC,D…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
