什么是AQS(AbstractQueuedSynchronizer)
一句话:
AQS 是一个用来构建锁和同步器的“线程排队管理框架”。
他主要复制三件事:
- 管理锁状态
- 管理线程等待队列
- 管理线程阻塞与唤醒
AQS 的整体结构
AQS
│
├── state(同步状态)
├── CLH队列(等待线程队列)
└── CAS操作(保证线程安全)
第一个核心:state(锁状态)
AQS内部有一个变量:
private volatile int state;
他表示锁的状态
在互斥锁中
state = 0 没有线程持有锁
state = 1 有线程持有锁
线程想要获取锁时:会用CAS操作
CAS(state,0,1)
成功说明拿到锁;失败说明锁被别人占用了。
第二个核心:等待队列
如果没抢到锁;就推进到第二步。
进入等待队列
AQS使用的是:
CLH队列
结构:Head -> Node -> Node -> Node
每给Node表示:一个等待锁的进程
比如:
线程1 拿到锁
线程2 排队
线程3 排队
线程4 排队
队列结构:
Head -> T2 -> T3 -> T4
第三个核心:线程阻塞和唤醒
线程进入等待队列中不会一直运行,而是:
被挂起(park)
AQS使用:
LockSupport.park()
使线程进入:休眠状态
等待锁释放时:
LockSupport.unpark()
唤醒队列中的线程。
流程图:
线程抢锁
↓
失败
↓
进入队列
↓
park阻塞
↓
锁释放
↓
unpark唤醒
完整执行流程
三个线程:
T1
T2
T3
第一步
T1来获取锁:
state=0
cas成功
T1 获得锁。
第二步
T2 来获取锁:
state = 1
CAS失败
于是:T2进入队列
队列:
Head -> T2
T2:
park()
睡眠
第三步
T3 来获取锁
同样失败:
Head -> T2 -> T3
T3 也:
park()
第四步
T1 释放锁:
state = 0
然后唤醒队列:
unpark(T2)
T2被唤醒后:再次尝试:CAS(state,0,1)
成功获得锁。
AQS 是怎么被使用的
AQS本身不是锁。
是:
锁的实现框架
很多并发工具都是基于AQS实现的:
ReentrantLock
Semaphore
CountDownLatch
ReentrantReadWriteLock
这些类都会:继承AQS
然后实现两个核心方法:
tryAcquire()
tryRelease()
AQS负责:
排队
阻塞
唤醒
AQS 最核心的设计思想

面试
AQS是java并发包中的同步框架,他通过一个volatile的state变量表示同步状态,并使用CLH队列管理等待线程,通过CAS操作保证线程安全,同时利用park/unpark实现线程阻塞与唤醒,从而为ReentrantLock、Semaphore、CountDownLatch 等同步器提供基础实现。
CAS和AQS的关系
上面我们讲到了CAS,现在讲讲CAS和AQS的关系
为了保证线程安全我们通常有两种操作;
第一:加锁
第二无锁并发
这就是CAS
CAS是一种乐观锁思想
我们可以理解为:
我任务没人会修改这个值了,如果有人改了,我就重试。
什么是CAS
CAS操作需要三个值:
CAS(内存值, 期望值, 新值)
执行逻辑:
如果 内存值 == 期望值
修改为 新值
否则
修改失败
例如:
state = 0
线程想改为:
1
执行:
CAS(0,1)
如果:
state 还是 0
说明没人改过:
成功
如果:
state 已经变成 1
说明别人改了:
失败
线程就会:
重新尝试
CAS 和 AQS 的关系
AQS 在修改 state 的时候,并不会用:synchronized
而是用CAS
CAS 是 AQS 修改 state 的原子操作基础,而 AQS 是基于 CAS 构建的线程同步框架。
CAS → 原子操作工具
AQS → 并发框架




