AQS 原理极简版 + ReentrantLock 加锁 / 解锁
·
一、AQS 的简介
AQS = AbstractQueuedSynchronizer(抽象队列同步器)是 JUC 锁(ReentrantLock、Semaphore、CountDownLatch 等)的底层核心骨架。
它只干三件事:
- 用一个 state 变量表示锁状态(0 = 无锁,1 = 已加锁,>1 = 重入)
- 用一个 exclusiveOwnerThread 记录当前持有锁的线程
- 用一个 CLH 变体双向队列 存放抢不到锁的线程
简单记:state(状态) + 队列(等待) + CAS(抢锁) = AQS
二、AQS 核心结构
state: int // 锁状态
exclusiveOwnerThread: Thread // 持有锁的线程
waiter: Node // 等待队列头尾指针
Node 节点里存:
- 线程对象
- 等待状态(CANCELLED / SIGNAL / CONDITION 等)
- prev /next 指针(双向链表)
三、ReentrantLock 非公平锁加锁流程(最常考)
1.lock () 完整流程
-
第一次 CAS 尝试把 state 从 0 → 1
- 成功:直接拿到锁,设置
exclusiveOwnerThread = 当前线程 - 失败:进入下一步
- 成功:直接拿到锁,设置
-
判断是不是锁重入当前线程 == 持有锁线程?
- 是:state + 1(可重入),直接返回
- 否:进入下一步
-
加入 AQS 等待队列
- 封装成 Node 节点,尾插法入队
- 再尝试一次抢锁(看前节点是不是 head)
-
抢不到就阻塞
- 调用
LockSupport.park(this)线程休眠 - 等待被唤醒
- 调用
2.解锁流程 unlock ()
- state - 1
- 如果 state == 0:
- 清空持有线程
exclusiveOwnerThread = null - 唤醒队列队首第二个节点(head.next)
- 清空持有线程
- 如果 state > 0:
- 说明是重入,只减计数,不唤醒
四、公平锁 vs 非公平锁
- 非公平锁(默认)上来直接 CAS 抢,不看队列,抢到就用 → 吞吐量高
- 公平锁上来先看队列有没有人排队 → 有就乖乖排队,绝不插队 → 不会线程饥饿,但慢一点
五、一张图看懂整套流程
线程调用 lock()
↓
CAS(state:0→1) 成功?
├─是 → 持有锁,结束
└─否 → 判断是不是重入
├─是 → state++,结束
└─否 → 封装 Node 入队
↓
再试抢锁
↓
抢不到 → park() 阻塞
↓
被前节点唤醒 → 再次抢锁
↓
抢到 → 出队、执行业务
↓
unlock() → state--
↓
state=0 → 唤醒后继节点
六、面试必背 5 句 AQS 核心总结
- AQS 是 JUC 锁的底层框架,靠 state + 队列 + CAS 实现
- ReentrantLock 底层就是 AQS 的独占模式
- 加锁:CAS 抢锁 → 重入判断 → 入队阻塞
- 解锁:state 递减 → 唤醒队列线程
-
公平锁看队列,非公平锁直接抢
更多推荐




所有评论(0)