1、AQS是什么
AQS全程AbstractQueuedSynchronizer(抽象队列同步器)。他是Java并发包(java.util.concurrent)中的一个核心组件,用来构建锁和其他工具(比如信号量...等)。你可以把它理解为一个“锁的框架”。很多锁(ReentrantLock,ThreadPoolExecutor,阻塞队列,CountDownLatch,Semaphore,CyclicBarrier....)都是基于AQS实现的。
2、AQS的核心思想
- 它的内部维护了一个state变量,用着变量来表示锁的状态。
- 🌰举例: state = 0 表示锁是空闲的;state = 1 表示锁被占用
- 它还有一个等待队列,用来存放没有竞争到锁资源的线程。这些线程会排队等待,直到锁资源被释放。
3、state变量和CAS
AQS中的state用来表示锁的状态
🌰举例:
- state = 0 ,表示锁没有被任何线程占用
- state > 0 ,表示锁被某个线程占用,state的值可以表示锁被重入的次数(比如ReentrantLock是可重入锁,一个线程可以多次获取同一把锁)。
CAS在并发编程的三大特性中-如何保证并发编程的原子性中有说到。不了解可以去看看 ->跳转。
4、ReentrantLock和AQS的关系
ReentrantLock
是Java中的一个锁实现,它的底层就是基于AQS的。ReentrantLock
的核心功能(比如加锁、解锁)都是操作AQS的state变量和等待队列实现的。
- 加锁
- 当线程调用lock()方法时,
ReentrantLock
会通过AQS的CAS操作尝试修改state变量。- 若state = 0, 就把state改成1,表示锁被占用了。
- 若state > 0, 就说明锁已经被占用了,当前线程进入等待队列。
- 当线程调用lock()方法时,
- 解锁
- 当线程调用unlock()方法时,
ReentrantLock
会把state变量 -1 ,若state = 0,表示锁已经被释放了,AQS会从等待队列中唤醒下一个线程来获取锁。
- 当线程调用unlock()方法时,
5、通俗比喻
你可以把 AQS 想象成一个“排队管理系统”:
-
state 变量:就像是一个“房间的门锁”。state = 0 表示门是开着的,state = 1 表示门是关着的。
-
等待队列:就像是一个“排队等候区”。如果门是关着的,新来的线程就要去排队等候。
-
CAS 操作:就像是“抢门锁”的动作。每个线程都尝试去抢门锁,如果抢到了就进门,抢不到就去排队。
ReentrantLock
就是基于这个“排队管理系统”实现的锁。它通过 CAS 操作来抢门锁,抢不到就去排队,等到锁被释放了再尝试抢。
6、总结
AQS:是一个锁的框架。提供了state变量和等待队列来管理锁的状态和线程的排队。
state:是一个变量,用来表示锁的状态。通过CAS操作来保证线程的安全。
ReentrantLock:是基于AQS实现的锁,利用AQS的state和等待队列来实现加锁、解锁的功能。