AQS源码解析

今天清明节放假正好趁此总结一下AQS的源码分析😊😊😊

AbstractQueuedSynchronizer 的简称,Doug Lea大师编写的AQS源码,其实就是对CAS的封装和丰富,用于实现同步器(如锁和信号量等)的基础框架

其实就是一个通用的同步框架,设置这样一个框架要满足以下几点:

  • 通用性:在实现底层必要的同步机制后,给上层调用留有空间,也就是保持对外接口的简单性和纯粹性
  • 利用CAS,原子的修改共享标志位
  • 等待队列:让队列的头部进行自旋获取标志位,而其他的线程则挂起

AQS的一个成员变量state,就是来判断共享资源是否被占用的标志位,设置为int类型是为了记录重入的次数,还有就是共享模式下表示线程的数量

然后它还有一个表示队列头尾的head、tail指针,这两个指针维护了一个FIFO的双向链表来对线程进行管理

java 复制代码
 1 private transient volatile Node head;
 2 private transient volatile Node tail;

队列中的每一个节点Node其实就是对线程的封装,其中也包括四种线程在队列中的等待状态,然后Node中方法也很简单,其中有一个就是获取前置Node

队列中的节点有两种模式,共享和独占,我说一下独占把,ReentrantLock底层就是基于独占模式的AQS来实现的

我们设计这样一个框架其实有两种主要的使用场景:

  • 尝试获得锁,不管有没有获得立即返回
  • 必须获得锁,如果当前锁被占用,则进行等待

源码中的tyrAcquire和acquire正好对应了这两种场景:

tyrAcquire在AQS中是直接抛出异常,是为了让使用的上层自己实现,因为在尝试获得锁的过程中可能包含业务自定义的逻辑,比如是否可重入

acquire方法是重要的,acquireQueued(addWaiter(Node.EXCLUSIVE),arg)

addWaiter(Node.EXCLUSIVE),arg方法是将当前线程封装为一个Node,然后加入等待队列,因为是符合FIFO的,所以通过CAS操作将Node添加到队尾

这里它采用了快速插入的机制,就是一开始先假设并发量比较少(就是前置节点不为空)的情况下CAS进行插入,如果插入失败,则执行enq(node);方法来循环尝试插入

在队列中插入成功后返回一个Node,接下来就是acquireQueued方法

它首先去拿当前节点的前置节点,如果前置节点为head,说明是队首然后当前节点有权限来尝试获得锁,如果不是队首,然后看当前线程是否需要挂起等待,如果需要就挂起等待,如果不需要则继续循环判断是否有权限来尝试获得锁

当前线程是否需要挂起等待的逻辑:

它判断它的前置节点是否也在等待获得锁,如果是,则当前这个线程就挂起等待,如果当前线程是取消状态,则从队列中取消该节点

如果判断当前节点需要被挂起,则执行下面方法:

就是将当前线程挂起阻塞在这,一直等到持有锁的线程来调用relese方法来唤醒

大量线程挂起,然后得有relese释放,来看一下relese的释放:

和tryAcquire一样,它的tryRelese也是交给上层去实现

主要是relese方法,来看unparkSuccessor方法是怎么释放的:

它是从队尾依次向前搜索,找到head后面最靠前的并且是非CANCELED的节点来唤醒,调用unpark

从后往前搜索是为了避免在多线程下新建Node节点时没有与后面节点建立Next连接导致搜索中断

相关推荐
程序员cxuan1 小时前
Codex 会把磁盘给烧了?完整复盘来了!
人工智能·后端·程序员
ClouGence2 小时前
Oracle 数据同步为什么会出现数据不一致?长事务是常被忽略的原因
数据库·后端·oracle
快乐肚皮2 小时前
深入理解Loop Engineering
前端·后端
小兔崽子去哪了2 小时前
Vue3 + Pinia 集成 IGV.js 实现 BAM 文件在线浏览
javascript·vue.js·后端
孟陬3 小时前
Claude Code 巧思 `Ctrl+S` 暂存键
前端·后端
雪隐3 小时前
个人电脑玩AI-06让5060 Ti给你打工——不光能画画,Qwen3-TTS还能学人说话,连我老板都信了!
人工智能·后端·python
Oneslide3 小时前
openEuler 17.1GB Everything ISO 离线本地 DNF 源搭建教程
后端
蝎子莱莱爱打怪3 小时前
那不是我的黑历史,那是我的来时路啊!😭😭
后端·程序员
用户298698530143 小时前
Java 实现 Word 文档文本与图片提取的方法
java·后端
蝎子莱莱爱打怪3 小时前
XZLL-IM干货系列 04|Netty 长连接实战:Pipeline 怎么排、心跳怎么跳、连接怎么管
后端·微服务·面试