JUC之AQS

JUC之AQS

AQS 是 AbstractQueuedSynchronizer 的缩写,它是 java.util.concurrent(JUC)包中一个至关重要的 抽象类 ,可以理解为实现同步器(锁、信号量等)的"万能框架"。

你可以把它看作是 Java 并发包中众多同步工具背后的底层基础设施ReentrantLockCountDownLatchSemaphore 等我们常用的并发工具,都是基于 AQS 构建的。

核心思想:资源共享与同步状态

AQS 的核心是解决了两个关键问题:

  1. 资源如何共享? ------ 同步状态(state)
  2. 没有抢到资源的线程怎么办? ------ 等待队列
1. 同步状态 (state)

AQS 使用一个 volatile int state 来表示共享资源。你可以根据需求赋予它不同的含义:

  • ReentrantLock 中,state = 0 表示锁未被占用,state > 0 表示被占用,且数值可以表示重入次数。
  • Semaphore 中,state 表示剩余的许可证数量。
  • CountDownLatch 中,state 表示还需要等待的计数。

通过 getState(), setState(), compareAndSetState() 这三个原子操作方法来修改状态。

2. CLH 等待队列

当线程获取同步状态失败时,AQS 会将其封装成一个 Node 节点,并放入一个 先进先出(FIFO)的双向队列 中。这个队列是 AQS 实现等待/通知机制的关键。

队列中的线程会被阻塞(LockSupport.park()),当同步状态释放时,AQS 会从队列头部唤醒等待的线程(unpark())。

两大资源共享模式

AQS 为子类提供了两种主要的工作模式:

模式 说明 典型代表
独占模式 只有一个线程能持有同步状态。 ReentrantLock
共享模式 多个线程可以同时持有同步状态。 CountDownLatch, Semaphore, ReadWriteLock 的读锁

AQS 中的队列同时支持这两种模式,Node 节点会标记自己是 SHARED 还是 EXCLUSIVE

关键设计:模板方法模式

AQS 是一个抽象类,它定义好了"骨架逻辑"(比如获取资源失败后如何排队、阻塞),但把"如何判断资源是否可用"这个具体逻辑,留给子类去实现。

你只需要重写 AQS 提供的几个特定方法,AQS 的 acquirerelease 等模板方法就会自动调用它们:

  • tryAcquire(arg):独占式尝试获取状态(需子类实现)
  • tryRelease(arg):独占式尝试释放状态(需子类实现)
  • tryAcquireShared(arg):共享式尝试获取状态(需子类实现)
  • tryReleaseShared(arg):共享式尝试释放状态(需子类实现)
  • isHeldExclusively():判断当前线程是否独占资源

一个简化的例子:理解如何使用 AQS

假设我们想实现一个简单的互斥锁(一次只允许一个线程进入),可以这样利用 AQS:

java

复制代码
// 1. 定义一个同步器类,继承 AQS
class MutexSync extends AbstractQueuedSynchronizer {
    // 尝试获取锁:将 state 从 0 改为 1
    @Override
    protected boolean tryAcquire(int arg) {
        return compareAndSetState(0, 1);
    }

    // 尝试释放锁:将 state 从 1 改为 0
    @Override
    protected boolean tryRelease(int arg) {
        setState(0);
        return true;
    }

    // 当前是否处于占用状态
    @Override
    protected boolean isHeldExclusively() {
        return getState() == 1;
    }
}

// 2. 定义锁的公开接口,使用 AQS 提供的模板方法
public class SimpleLock {
    private final MutexSync sync = new MutexSync();

    public void lock() {
        // 调用 AQS 的模板方法,它会调用我们重写的 tryAcquire
        sync.acquire(1); 
    }

    public void unlock() {
        // 调用 AQS 的模板方法,它会调用我们重写的 tryRelease
        sync.release(1);
    }
}

你不需要关心排队、阻塞、唤醒等复杂的底层逻辑,AQS 都为你处理好了。

总结:AQS 的价值

  • 对开发者 :提供了构建锁和同步器的标准化模板,复用了高质量的并发控制代码,避免重复造轮子。
  • 对 JUC 框架 :是整个 java.util.concurrent 包的基石 ,支撑起了 ReentrantLockCountDownLatchSemaphore 等众多高级工具。
  • 对学习并发 :理解 AQS 的 state 状态和 CLH 队列,是深入理解 Java 并发机制的关键一步。
相关推荐
Java搬码工34 分钟前
CompletableFuture 完整详解 + 全场景使用案例
java
许心月40 分钟前
Java学习资料网站汇总
java
c2385644 分钟前
第二篇:《测试指挥官:可视化单题自测框架(含 assert 实操)》
java·数据库·c++·算法·安全性测试
辞旧 lekkk1 小时前
【Redis初阶】常见数据类型
开发语言·数据库·c++·redis·学习·缓存·bootstrap
帅次2 小时前
Kotlin 与 Java 互操作:混合工程里的平台类型与 API 边界
java·开发语言·kotlin·suspend·nullable
X-⃢_⃢-X2 小时前
一、第一阶段:认识 Spring Boot
java·spring boot·后端
前端工作日常2 小时前
我学习到的Java程序的生命周期
java·后端
SunnyDays10112 小时前
Java 实现 PDF 页面删除、排序、旋转和裁剪
java·pdf
人工干智能3 小时前
科普:Pandas 索引器 loc 与 iloc 的编程思维
java·人工智能·pandas
dtq04243 小时前
C语言-结构体详解
c语言·开发语言·学习