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 并发机制的关键一步。
相关推荐
Zella折耳根几秒前
Java 正则表达式实战:IP 地址匹配与替换全解析
java·tcp/ip·正则表达式
摇滚侠几秒前
JavaWeb 全套教程 Filter 107-111
java·开发语言·servlet
YIN_尹3 分钟前
【Linux系统编程】基础IO第一讲——系统文件IO
android·java·linux·c++
聆风吟º3 分钟前
【C标准库】深入理解C语言 atoi 函数:字符串转换为整数
c语言·开发语言·库函数·atoi
凤山老林4 分钟前
81-Java Scanner 类
java·开发语言
j_xxx404_4 分钟前
MySQL数据库基础硬核解析:从 C/S 网络服务到磁盘文件与存储引擎
linux·运维·服务器·开发语言·数据库·mysql·ai
艾莉丝努力练剑4 分钟前
【QT】系统相关:QT文件
linux·服务器·开发语言·网络·qt·tcp/ip·计算机网络
linge_sun6 分钟前
Sping AI 使用 Ollama 快速搭建本地知识库
java·人工智能·ai编程
沐苏瑶6 分钟前
深入浅出 Java 文件操作与 IO:从文件系统到数据流实战
java·开发语言
海鸥-w8 分钟前
用python (fastapi)做项目第二天实现新闻列表和新闻详情接口
开发语言·python·fastapi