871 字
约 2 分钟
5
S05-J01 · AQS 与 ReentrantLock 源码
2024-12-31
2026-11-07

适用读者:想知道 ReentrantLock 凭什么比 synchronized 灵活的人。
前置:S05-B03。
实测环境:OpenJDK 21.0.12.1(2026-11-05)。
覆盖旧文:A-1122(312) A-1123(227) A-1121(217) A-1595(340) + 1582(111) 945(75) 1601(77) = 1,359 点。
覆盖扩展:E-S05-008(state 与 CLH 队列)。
上一篇:S05-B05 · 线程池:7 个参数、拒绝策略与动态调整
下一篇:S05-J02 · 并发容器。


1. 一句话结论

AQS = 一个 volatile int state + 一个双向等待队列(CLH 变体)。所有同步器(ReentrantLock/Semaphore/CountDownLatch)都只是"怎么解释 state"。


2. 结构(E-S05-008)

组件 作用
volatile int state 同步状态(ReentrantLock 里 = 重入次数)
CLH 双向队列 等锁线程排队(Node 含 prev/next/waitStatus)
tryAcquire/tryRelease 由子类实现(独占)
tryAcquireShared/tryReleaseShared 共享模式(Semaphore/CountDownLatch)

"独占 vs 共享"是 AQS 的唯一分野:

模式 例子 state 含义
独占 ReentrantLock 重入次数
共享 Semaphore 剩余许可数

3. 实测:可重入与 tryLock

ReentrantLock lock = new ReentrantLock(true);  // 公平
lock.lock(); lock.lock();
System.out.println(lock.getHoldCount());      // → 2

实测输出:

1. 可重入 holdCount = 2
2. tryLock(200ms) 对端持有 800ms → false
事实 说明
holdCount = 2 state 累加,同一线程可重入
tryLock(200ms) → false 超时拿不到就返回 false(不会一直等)

这两个能力 synchronized 都没有:它是"要么阻塞到拿到,要么拿不到就阻塞",没有"等 200ms 不给我就走"。


4. 公平锁 vs 非公平锁(A-1121)

类型 行为 代价
非公平(默认) 新来的线程可直接抢(插队) 可能饿死排队线程,但吞吐更高
公平 严格按队列顺序 吞吐略低(每次要检查队列)

实测佐证:new ReentrantLock(true) 是公平锁;默认 new ReentrantLock() 是非公平。

判据:"能否容忍个别线程长时间拿不到锁?" 不能 → 公平;否则用非公平(默认)。


5. tryLock 的三种用法

if (lock.tryLock()) { ... }                              // 立即返回
if (lock.tryLock(200, TimeUnit.MILLISECONDS)) { ... }    // 超时
if (lock.tryLock(200, MS)) { } else { 降级逻辑 }          // 拿不到就降级

典型场景:避免死锁——用超时拿不到的线程主动放弃并重试,破坏"循环等待"。


6. 五个误区

误区 真相
"AQS 是锁" 是同步器框架,锁只是其中一种
"公平锁一定更好" 吞吐更低,默认非公平
"tryLock 不阻塞" 无参不阻塞;带超时会最多等那么久
"unlock 可以省略" 必须 finally,否则永久占用
"holdCount 不会为 0" 每次 unlock 减 1,归零才真正释放

7. 自检

  1. AQS 的两个核心组成是什么?
  2. 独占与共享模式的差别?各举例。
  3. 公平锁与非公平锁的取舍?
  4. tryLock 怎么用来避免死锁?
  5. 为什么 unlock 必须写在 finally?

8. 下一篇

S05-J02 · 并发容器:CHM、阻塞队列、COW

AQS 讲完,下一篇讲"不用锁也能安全"的容器:ConcurrentHashMap 为什么在 JDK 8 废弃分段锁、COW 适合什么场景。


本篇属于系列《S05 · Java 并发与 JVM》。旧文来源:A-1122/1123/1121/1595/1582/945/1601;扩展点 E-S05-008。实测为 OpenJDK 21。

S05-J01 · AQS 与 ReentrantLock 源码
https://www.clxhxhhr.top/posts/5247/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。