当前位置: 首页 > 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.zskr.cn/news/20993.html

相关文章:

  • 2025 年清洗机厂家最新推荐:高压清洗机、超声波清洗机等多类型设备企业品牌权威榜单,帮企业高效筛选优质清洗设备
  • 从零开始:用C#开发的海量文件内容秒搜神器TDSContent——免费开源高效办公必备!
  • 2025 旋转蒸发仪选型指南:适配科研与生产需求的优质厂家 TOP5 推荐
  • 移动终端安全:实验2-创建自签名证书对APP签名 - 详解
  • Day3整形输入
  • 2025优质电缆/防火/模压/瓦楞/大跨距/热镀锌/热浸锌/不锈钢/光伏/铝合金/锌铝镁桥架厂家推荐:五家实力企业的技术与服务特色解析
  • 2025 领域优质石油/电厂/钢铁厂/化工/消防/船舶/住宅/管道/隧道/地铁电伴热带厂家推荐榜单,工业与民用场景全覆盖
  • 2025年10月学术会议全名单!科研人请抢先收藏,别错过关键节点!
  • python对比“解包赋值”和 match 语句中的“解构”
  • 观点分享:Oracle数据库GRID升级的案例的闲聊
  • 2025 佛山高尔夫模拟器厂家推荐:从家庭到专业场景的靠谱之选
  • 高速采集卡:解锁海量数据洪流,驱动精准测量新时代
  • 基于MATLAB的HOG+SVM行人检测
  • 网络文件共享系统NFS服务搭建
  • C# 泛型懒汉单例类
  • MyEMS 支撑公共建筑低碳运营:多维度能耗建模逻辑与运行优化策略
  • 实时检测机器人广告点击的深度学习技术
  • 开源生态视角下 MyEMS 的能源管理系统国产化实践:架构设计与自主可控路径
  • 【IEEE出版】第七届机器学习、大数据与商务智能国际会议(MLBDBI 2025)
  • 2025 年国内优质货代公司最新推荐排行榜:深度解析头部企业服务能力,助力企业精准选合作伙伴泰国货代/印尼货代/马来货代/日本货代/东南亚货代公司推荐
  • 国标GB28181算法算力平台EasyGBS在食品安全监管系统中的融合与应用方案
  • springcloud和dubbo有什么区别
  • mysql默认事务隔离级别,从入门到精通的完全指南
  • 利用 OpenTelemetry 集成 JMX 监控
  • 深入浅出 Go slices 包:类型安全、内存安全与高性能实践
  • 斑马日记2025.10.10
  • 入门指南:使用 Playwright MCP Server 为你的 AI Agent 赋予浏览器自动化能力
  • 实战教程:构建能交互网页的 AI 助手——基于 Playwright MCP 的完整项目
  • 达梦开启awr功能报错:[-7160]:Object [DBMS_WORKLOAD_REPOSITORY_DATA_LOW] is invalid
  • ceph日常管理