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

深入理解 AbstractQueuedSynchronizer(AQS):构建高性能同步器的基石 - 指南

AbstractQueuedSynchronizer(简称 AQS)是 Java 并发包(java.util.concurrent)中最核心的基础类之一,几乎所有自定义的同步器(如 ReentrantLockCountDownLatchSemaphoreFutureTask 等)都直接或间接地基于 AQS 实现。

本文将深入探讨 AQS 的核心设计思想、内部数据结构、关键方法实现、以及它背后的并发控制模型。


一、AQS 的核心设计思想

AQS 提供了一个 队列式的、基于状态的同步框架,它的设计思想非常明确:

基本模型:

通过维护一个 volatile 的 state 变量来表示同步状态,并用一个 FIFO 队列管理等待线程。

具体来说,它实现了两种锁的语义:

开发者通过继承 AQS 并重写其 tryAcquire / tryRelease 等方法来实现自定义的同步逻辑,而不需要关心线程挂起/唤醒的底层细节。


️ 二、AQS 的关键内部结构

1. state 变量(同步状态)

private volatile int state;

这是 AQS 的核心状态变量,通常用来表示资源是否可用、计数器大小等。子类通过 getState() / setState() / compareAndSetState() 来访问和修改它。


2. CLH 队列(等待队列)

AQS 使用一种变种的 CLH(Craig, Landin, and Hagersten)锁队列 来维护所有正在等待获取锁的线程。

static final class Node {
volatile Node prev;
volatile Node next;
volatile Thread thread;
volatile int waitStatus;
}

常见的 waitStatus 值:

  • 0:默认状态
  • SIGNAL (-1):后继节点等待唤醒
  • CANCELLED (1):线程取消等待
  • CONDITION (-2):表示在 condition 上等待
  • PROPAGATE (-3):共享模式传播

队列头尾指针:

private transient volatile Node head;
private transient volatile Node tail;

AQS 通过 enq()acquireQueued() 等方法管理队列入队/出队与线程阻塞/唤醒的逻辑。


⚙️ 三、核心方法详解

1. acquire(int arg):独占模式获取

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

流程如下:

  • 首先尝试获取锁(调用子类实现的 tryAcquire());
  • 获取失败则将当前线程包装成 Node 并加入等待队列;
  • 在队列中自旋等待,并最终阻塞(LockSupport.park());
  • 直到被前驱唤醒并重新竞争资源。

2. release(int arg):独占模式释放

public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
  • 调用子类的 tryRelease() 释放资源;
  • 如果成功,唤醒等待队列中的下一个线程。

3. acquireShared(int arg) / releaseShared(int arg)

共享模式下的获取和释放,允许多个线程同时访问资源(如信号量)。

public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}

四、自定义同步器的三大步骤

要实现一个自定义同步器,一般遵循以下步骤:

1. 继承 AbstractQueuedSynchronizer

class MyLock extends AbstractQueuedSynchronizer {
...
}

2. 实现同步逻辑(重写关键方法)

protected boolean tryAcquire(int arg) {
// 例如实现不可重入独占锁
return compareAndSetState(0, 1);
}
protected boolean tryRelease(int arg) {
setState(0);
return true;
}

3. 暴露锁 API 给外部调用

public void lock() {
acquire(1);
}
public void unlock() {
release(1);
}

五、AQS 的典型应用场景

类名功能AQS 模式
ReentrantLock可重入独占锁独占
Semaphore信号量共享
CountDownLatch倒计时器共享
ReadWriteLock读写锁独占 + 共享
FutureTask任务状态管理独占

这些类都封装了 AQS 提供的同步能力,让我们得以用更高层的 API 进行线程协作。


六、深入理解:CLH 队列与线程挂起/唤醒

✴️ 挂起线程:LockSupport.park()

当线程获取锁失败,就会调用 LockSupport.park(this) 挂起自己。

✴️ 唤醒线程:LockSupport.unpark(thread)

释放锁后,会唤醒队列中的下一个节点对应的线程。

这是一种 显式挂起-唤醒机制,相比传统 wait/notify 更加灵活和安全,不依赖对象 monitor。


七、AQS 存在的问题和挑战

  • 非公平锁可能导致线程“饿死”
  • 锁竞争激烈时,自旋+挂起开销大
  • 调试困难,出错后难以定位问题源头
  • 死锁风险高,一旦 tryAcquire 实现不当容易出问题;

因此,在使用 AQS 时,强烈建议封装为高层 API 使用,不要轻易手写同步器,除非非常熟悉。


✅ 总结

特性描述
模型基于状态的同步器
队列CLH 队列实现等待线程排队
支持独占与共享两种模式
控制点子类重写 tryAcquire / tryRelease 等控制同步行为
应用ReentrantLock、Semaphore、CountDownLatch、FutureTask 等

推荐阅读与资料

  • 《Java 并发编程实战》(Java Concurrency in Practice)
  • Doug Lea 的 AQS 原始设计文档
  • JDK 源码中的 AbstractQueuedSynchronizer.java 注释
  • 博客:Martin Fowler 的并发模式分析

http://www.hskmm.com/?act=detail&tid=31016

相关文章:

  • 2025 年清洗机厂家最新推荐:高压清洗机、超声波清洗机等多类型设备企业品牌权威榜单,帮企业高效筛选优质清洗设备
  • 隐藏继承成员什么时候用到
  • 2025 旋转蒸发仪选型指南:适配科研与生产需求的优质厂家 TOP5 推荐
  • 今天被公司告知不续签合同了,我被优化了 哈哈哈
  • 2025 年混合机厂家最新推荐排行榜:强力混合机 / 倾斜式混合机 / 耐火材料混合机 / 锂电池材料混合机 / 球团强力混合机优质厂家推荐
  • Oracle OCM 认证的定位与价值
  • 2025 优质防爆接线盒/防爆穿线盒/防爆接电箱厂家推荐榜:安全与专业兼具的行业之选
  • 实验2 C语言分支与循环基础应用编程
  • Microsoft Purview实现数据泄露概率降低30%的技术解析
  • Day13-C:\Users\Lenovo\Desktop\note\code\JavaSE\Basic\src\com\exception
  • 2025 值得关注的除锈剂厂家企业推荐榜单,覆盖多场景需求
  • Day3整形输入
  • 2025优质电缆/防火/模压/瓦楞/大跨距/热镀锌/热浸锌/不锈钢/光伏/铝合金/锌铝镁桥架厂家推荐:五家实力企业的技术与服务特色解析
  • 2025 领域优质石油/电厂/钢铁厂/化工/消防/船舶/住宅/管道/隧道/地铁电伴热带厂家推荐榜单,工业与民用场景全覆盖
  • 高效驱动 IC 设计的关键 - RTL 合成
  • m-lag
  • springboot实现支付宝支付
  • Pendle Finance 详解:DeFi 中的“收益拆分器”——新手指南
  • 阅读笔记1
  • 17
  • springboot实现微信支付
  • Hyperliquid 主链的技术栈详解
  • trading
  • pringcloud 中的gateway详解一下,其中的原理
  • Hive -2025/8/19
  • MyBatisPlus
  • 2025年10月学术会议全名单!科研人请抢先收藏,别错过关键节点!
  • 用 Python + Vue3 打造超炫酷音乐播放器:网易云歌单爬取 + Three.js 波形可视化
  • 读书笔记:时间戳(TIMESTAMP)类型:比日期更强大的时间管理工具
  • python对比“解包赋值”和 match 语句中的“解构”