AQS通过state变量、FIFO队列、CAS和自旋实现独占锁:lock()先tryAcquire,失败则addWaiter入队并acquireQueued自旋挂起;unlock()调用tryRelease释放锁,成功后unparkSuccessor唤醒后继。

AQS(AbstractQueuedSynchronizer)通过 state 状态变量 + FIFO 同步队列 + CAS + 自旋等待 三者协同实现独占锁的 lock() 与 unlock(),核心在于线程如何竞争、排队和唤醒。
lock():尝试获取锁,失败则入队挂起
调用 ReentrantLock.lock()(非公平模式)最终会走到 AQS 的 acquire(int arg) 方法:
- 先调用
tryAcquire(arg)—— 这是模板方法,由子类(如NonfairSync)实现;它用 CAS 尝试将state从 0 改为 1,成功即获得锁,直接返回 - 若失败(state ≠ 0),则执行
addWaiter(Node.EXCLUSIVE):将当前线程封装为独占节点,插入同步队列尾部 - 再调用
acquireQueued(node, arg):进入自旋。检查前驱是否为 head,若是则再次尝试tryAcquire;否则将前驱的waitStatus设为SIGNAL,然后调用LockSupport.park(this)挂起当前线程
unlock():释放锁并唤醒后继节点
调用 unlock() 最终进入 AQS 的 release(int arg):
- 先调用
tryRelease(arg)—— 子类实现(如Synx.tryRelease),将state减去对应值(可重入场景可能减多次),清空独占线程(setExclusiveOwnerThread(null)),返回true表示完全释放 - 若释放成功,则调用
unparkSuccessor(head):找到 head 的第一个有效后继节点(waitStatus ),调用LockSupport.unpark(node.thread)唤醒它 - 被唤醒的线程在
acquireQueued自旋中再次尝试获取锁,此时大概率成功(因为 state 已为 0)
关键细节不能忽略
这些设计让锁行为既高效又可靠:
- head 哨兵节点不关联线程:队列头始终是虚节点,真正等待的线程从 head.next 开始,避免唤醒逻辑复杂化
- waitStatus = SIGNAL 表示“请唤醒我”:前驱节点在挂起自己前,会把后继的 waitStatus 设为 SIGNAL,确保释放锁时能精准通知
- CAS + volatile 保证可见性与原子性:state 是 volatile,所有修改都通过 CAS,避免指令重排和脏读
-
可重入靠 state 计数 + 线程身份校验:
tryAcquire中判断当前线程是否已持有锁,是则 state++,不是才尝试抢占
公平锁 vs 非公平锁的区别点
两者都在 tryAcquire 实现里体现:
- 非公平锁:上来就 CAS 抢锁(插队),失败才进队——吞吐高,但可能饥饿
- 公平锁:先查队列是否为空或自己是否是头后第一个节点,满足才 CAS;否则直接入队——不插队,响应顺序更可预测
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











