当前位置: 首页 > news >正文

理解AQS的原理并学习源码

文章目录

  • 什么是AQS?
  • 核心功能
    • 状态管理
    • 线程等待
  • 加锁流程
  • 解锁流程
  • 共享模式
  • 总结

什么是AQS?

AbstractQueuedSynchronizer(抽象队列同步器)是Java并发包java.util.concurrent中的核心基础组件,它提供了一个用于构建锁和其他同步组件的框架,在其内部通过volatile int state变量表示同步状态,并且定义了一个内部类来使用双向链表实现等待队列,同时支持独占和共享模式。

核心功能

状态管理

AQS使用一个32位的整数来表示同步状态:

private volatile int state;

这个状态变量的含义完全由子类来定义。例如:在ReentrantLock中,state表示锁被持有的次数。

线程等待

如果被请求的共享资源空闲,则将当前的请求线程设置为有效的⼯作线程,然后将对应的共享资源设置为锁定状态。如果共享资源被占⽤,则通过CLH同步队列将暂时⽤不到的线程封装成⼀个节点加⼊到队列中,同时在适当的时候对其进⾏阻塞和唤醒。

加锁流程

以ReentrantLock的NonfairSync为例:

  1. 直接尝试CAS抢占

NonfairSync首先会直接尝试CAS将state从0设置为1:

final void lock() {if (compareAndSetState(0, 1)) // // 直接抢占setExclusiveOwnerThread(Thread.currentThread());elseacquire(1); // // 抢占失败,进入AQS流程}
  1. 进入AQS的acquire流程

如果CAS失败,调用acquire(1):

public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}
        protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}

再次调用tryAcquire()尝试获取锁(非公平特性体现):

final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}

如果当前线程已持有锁,增加重入次数;获取失败则进入队列等待。

  1. 加入等待队列
private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);// Try the fast path of enq; backup to full enq on failureNode pred = tail;if (pred != null) {node.prev = pred;if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}enq(node);return node;}

获取失败时,将线程包装成Node并通过CAS操作安全地加入队列尾部。

  1. 队列中自旋和阻塞

在队列中的处理逻辑:

final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}

检查前驱节点是否为head,如果是则尝试获取锁;如果获取成功则将自己设为新的head节点,获取失败则判断是否需要阻塞(shouldParkAfterFailedAcquire), 需要阻塞则调用LockSupport.park()挂起线程。

解锁流程

释放锁的代码:

protected final boolean tryRelease(int releases) {int c = getState() - releases;if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {free = true;setExclusiveOwnerThread(null);}setState(c);return free;}

将state减1,判断当前线程是不是独占线程,如果是就抛异常;当state变为0时,设置独占线程为null,并且后续返回true。

共享模式

除了独占模式,AQS还支持共享模式,其特点是多个线程可以同时持有资源,主要方法包括:

  • acquireShared(int arg):共享模式获取资源
  • releaseShared(int arg):共享模式释放资源

总结

AQS提供了一个用于构建锁和其他同步组件的框架,在其内部通过volatile int state变量表示同步状态,并且定义了一个内部类来使用双向链表实现等待队列,同时支持独占和共享模式。

http://www.xdnf.cn/news/1322965.html

相关文章:

  • 大厂 | 华为半导体业务部2026届秋招启动
  • Spark 运行流程核心组件(三)任务执行
  • 【lucene】tip文件详解
  • 08.常见文本处理工具
  • 基于Spring Boot+Vue的社区便民服务平台 智慧社区平台 志愿者服务管理
  • 咨询进阶——解读咨询顾问技能模型
  • QT 字节大小端转序方法
  • axure chrome 浏览器插件的使用
  • kafka的pull的依据
  • 关系型数据库与非关系型数据库
  • 冒泡排序——简单理解和使用
  • 嵌入式第三十一天(线程间的机制,IPC机制)
  • JAVA经典面试题:数据库调优
  • rust 从入门到精通之变量和常量
  • 从 ORA-12703 到顺利入库:Go + Oracle 11g GBK 字符集踩坑记20250818
  • [免费]基于Python的全国气象数据采集及可视化大屏系统(Flask+request库)【论文+源码+SQL脚本】
  • elasticsearch-集成prometheus监控(k8s)
  • 【LeetCode题解】LeetCode 74. 搜索二维矩阵
  • 【深度长文】Anthropic发布Prompt Engineering全新指南
  • IDE开发系列(2)扩展的IDE框架设计
  • 【音视频】瑞芯微、全志芯片在运动相机和行车记录仪产品分析
  • mybatis连接数据库
  • Kafka 零拷贝(Zero-Copy)技术详解
  • 数据赋能(401)——大数据——持续学习与优化原则
  • RAG 入门指南:从概念到最小系统搭建
  • 基于Android的随身小管家APP的设计与实现/基于SSM框架的财务管理系统/android Studio/java/原生开发
  • 从0-1使用Fastmcp开发一个MCP服务,并部署到阿里云百炼 -持续更新中
  • Flutter 自定义 Switch 切换组件完全指南
  • 深度学习——R-CNN及其变体
  • React diff——差异协调算法简介