引子:武林大会的“门派秘技”
话说江湖中,武林高手云集,各大门派都带着自己的独门秘籍来争夺武林至尊。而在 Java 的并发世界里,也有一个隐藏的“武林秘籍”,那就是 AQS(AbstractQueuedSynchronizer) 。
这套秘籍看似深奥,实则掌控着 Java 并发的半壁江山。无论是 ReentrantLock(可重入锁)、Semaphore(信号量)、CountDownLatch(倒计时器) ,还是 ReentrantReadWriteLock(读写锁) ,背后都离不开 AQS 的加持。
今天,小米就化身少林扫地僧,给大家掰开了、揉碎了,讲清楚 AQS 的“武学精髓”!
AQS 是什么?
AQS,全称 AbstractQueuedSynchronizer,是 JDK 并发包(java.util.concurrent)中用于构建锁和同步器的基础框架。
用武侠比喻,AQS 就像是一个 “武功心法” ,它本身并不直接用于战斗(业务开发),但几乎所有高级武学(锁、同步器)都基于它来实现。
AQS 的核心思想:CLH 队列
AQS 底层采用了一种叫 CLH(Craig, Landin, and Hagersten)队列 的数据结构,它本质上是一个 FIFO(先进先出) 队列,所有的竞争线程都会排队等候锁的释放。
在 Java 中,AQS 维护了一个 state 变量(代表锁的状态)和一个 等待队列(双向链表) ,当多个线程争夺锁时,就会按照 FIFO 规则排队等待。
一个关键点:AQS 采用的是“模板方法模式” 。也就是说,它定义了一整套 获取、释放资源的流程,但具体的实现(如加锁、解锁逻辑)是交给子类去实现的。
所以,AQS 不能直接使用,而是被 ReentrantLock、Semaphore、CountDownLatch 等类所继承,成为它们的核心实现机制。
AQS 的核心机制:独占锁 & 共享锁
AQS 是一个支持 独占模式(Exclusive) 和 共享模式(Shared) 的同步器。
1. 独占模式:江湖中的“独门秘籍”
在独占模式下,某个线程获取了锁后,其他线程只能干等着。
举个栗子:ReentrantLock 的独占锁实现
- tryAcquire(int arg):尝试获取锁,CAS 方式设置 state=1,成功返回 true,失败就进入等待队列。
- tryRelease(int arg):释放锁,把 state 置为 0,并唤醒后续线程。
这个 MyLock 就是最基础的 独占锁,它的实现机制和 ReentrantLock 如出一辙。
2. 共享模式:江湖中的“少林秘技”
在共享模式下,多个线程可以同时获取锁,但有一定的数量限制。
举个栗子:CountDownLatch 的共享锁实现
这个 MyLatch 实现了 共享模式,允许多个线程等待某个条件完成再继续执行。
- tryAcquireShared(int arg):当 state == 0 时,表示可以继续,否则线程进入等待队列。
- tryReleaseShared(int arg):CAS 方式减少 state,当 state == 0 时,唤醒所有等待的线程。
这就是 CountDownLatch 的基本原理!
AQS 的核心方法
在 AQS 里,所有锁的获取和释放,都是通过 acquire/release 方法来控制的。
AQS 通过这些方法,实现了 公平锁、非公平锁、自旋锁、可重入锁等各种锁机制,真正做到了 一套框架,适配万千武学。
AQS 的应用场景
既然 AQS 这么强大,那它到底被用在哪些地方呢?
1. ReentrantLock(可重入锁)
- 独占模式
- 用于高并发场景下的线程安全控制。
2. Semaphore(信号量)
- 共享模式
- 控制同时访问资源的线程数量,适用于限流场景。
3. CountDownLatch(倒计时器)
- 共享模式
- 让多个线程等待某个条件达成。
4. ReentrantReadWriteLock(读写锁)
- 独占模式(写)+ 共享模式(读)
- 适用于读多写少的场景,提高性能。
总结:AQS 是 Java 并发的“武林秘籍”
- AQS 是 Java 并发包的核心,提供了 独占模式 和 共享模式 两种方式。
- 底层基于 CLH 队列,线程竞争锁时会排队等待,提高性能。
- 基于 AQS,JDK 提供了 ReentrantLock、Semaphore、CountDownLatch 等同步工具,极大提高了并发编程的效率。
END
江湖路远,AQS 这本秘籍你学会了吗?如果你觉得这篇文章有帮助,记得 点赞、关注、转发,小米继续给你带来更多 Java 技术分享!
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!