一、AQS的两种模式:独占与共享
AQS通过tryAcquire/tryRelease和tryAcquireShared/tryReleaseShared两套方法,支持两种资源访问模式:
- 独占模式(Exclusive):资源仅允许一个线程持有(如ReentrantLock)。
- 共享模式(Shared):资源允许多个线程共同访问(如Semaphore、CountDownLatch)。
二、ReentrantLock:独占锁的实现
1. 核心代码解析
- state含义:表示锁的重入次数(0=未锁定,≥1=被持有)。
- Sync实现:
// ReentrantLock.Sync protected final boolean tryAcquire(int acquires) { // 实现重入逻辑(见前文) } protected final boolean tryRelease(int releases) { // 减少state,归零时释放锁 }
2. 特点
- 同一时刻只有一个线程能修改
state。 - AQS队列中所有节点均为
Node.EXCLUSIVE(独占模式)。
三、Semaphore:共享锁的流量控制
1. 核心代码解析
- state含义:表示可用许可证数量。
- Sync实现:
// Semaphore.NonfairSync protected int tryAcquireShared(int acquires) { return nonfairTryAcquireShared(acquires); } final int nonfairTryAcquireShared(int acquires) { for (;;) { int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) { return remaining; // 正数:获取成功;负数:需排队 } } } protected boolean tryReleaseShared(int releases) { for (;;) { int current = getState(); int next = current + releases; if (next < current) throw new Error("Maximum permit count exceeded"); if (compareAndSetState(current, next)) return true; } }
2. 特点
- 多个线程可同时获取许可证(
state减少),直到归零。 - AQS队列节点为
Node.SHARED,唤醒时会传播(连续唤醒后续共享节点)。
四、CountDownLatch:一次性栅栏
1. 核心代码解析
- state含义:初始值为计数阈值,递减至0时触发唤醒。
- Sync实现:
// CountDownLatch.Sync protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1; // 1=成功,-1=需阻塞 } protected boolean tryReleaseShared(int releases) { for (;;) { int c = getState(); if (c == 0) return false; int nextc = c - 1; if (compareAndSetState(c, nextc)) return nextc == 0; // 只有当state归零时返回true,触发唤醒 } }
2. 工作流程
- 初始化:
state = N(N为计数阈值)。 - countDown():调用
releaseShared(1),递减state,归零时唤醒所有等待线程。 - await():调用
acquireSharedInterruptibly(1),若state ≠ 0,线程进入队列阻塞。
五、三者的关键差异对比
| 维度 | ReentrantLock | Semaphore | CountDownLatch |
|---|---|---|---|
| 同步模式 | 独占 | 共享 | 共享 |
| state语义 | 重入次数 | 剩余许可证数量 | 剩余计数 |
| 资源释放 | 持有线程主动释放 | 获取许可证的线程均可释放 | 外部线程调用countDown() |
| 重用性 | 可重入,反复加锁/解锁 | 许可证可动态增减 | 一次性(归零后不可重置) |
| 典型场景 | 临界区互斥访问 | 限流(如数据库连接池) | 多线程等待事件触发 |
六、AQS的通用逻辑与定制扩展
1. 共性逻辑
- 队列管理:所有同步器共用同一套入队/出队、阻塞/唤醒逻辑。
- 中断与超时:由AQS统一处理,子类无需关心。
2. 定制扩展
通过重写以下方法实现不同同步语义:
- 独占模式:
protected boolean tryAcquire(int arg) protected boolean tryRelease(int arg) - 共享模式:
protected int tryAcquireShared(int arg) protected boolean tryReleaseShared(int arg)
七、总结:AQS的抽象力量
- ReentrantLock:通过
state和独占模式实现互斥性与重入性。 - Semaphore:利用共享模式和
state的原子操作,实现灵活的许可证管理。 - CountDownLatch:通过
state的递减和共享唤醒机制,构建一次性协作屏障。
源码启示:AQS通过抽象state的含义和操作,将复杂的线程调度封装为可复用的框架,这正是Java并发包高效且灵活的核心原因。