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 并发机制的关键一步。
相关推荐
Full Stack Developme1 小时前
Spring 模块介绍
java·后端·spring
沫璃染墨1 小时前
红黑树完全指南:从核心原理到插入验证全实现
开发语言·c++·算法
yu85939581 小时前
基于 QT5.7.0 的八线激光雷达点云聚类实现
开发语言·qt·聚类
多敲代码防脱发1 小时前
Spring进阶(BeanFactory与ApplicationContext)
java·数据库·spring boot·后端·spring
yoyo_zzm2 小时前
汇编到PHP:五大编程语言核心特性全解析
开发语言·汇编·php
吴声子夜歌2 小时前
Java——反射
java·反射
JAVA面经实录9172 小时前
完整版JVM 深度学习体系(二)
java·jvm
m0_702036532 小时前
html标签如何提升可访问性_aria-label与title区别【指南】
jvm·数据库·python
.ZGR.2 小时前
线程池相关知识及并发统计案例实现
java·开发语言