1. ReentrantLock 的设计背景与核心价值
在 Java 并发编程领域,锁机制是协调多线程访问共享资源的基础工具。synchronized 作为 Java 内置的关键字虽然简单易用,但在复杂场景下存在诸多限制。2004 年 JSR-166 引入的 java.util.concurrent 包中,ReentrantLock 作为其核心组件之一,提供了比 synchronized 更丰富的功能集。
关键设计考量:ReentrantLock 的诞生并非为了替代 synchronized,而是为开发者提供更细粒度的控制能力。其名称中的"Reentrant"(可重入)直接表明了它的核心特性——持有锁的线程可以重复获取同一把锁而不会造成死锁。
从架构层面看,ReentrantLock 采用了经典的模板方法模式,将锁的核心逻辑委托给内部同步器 Sync 实现。这种设计带来三个显著优势:
- 职责分离:锁的公共接口与具体实现解耦
- 扩展灵活:支持公平/非公平两种策略
- 性能优化:通过 AQS 的 CLH 队列减少竞争
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. AQS 深度解析:ReentrantLock 的基石
2.1 AQS 核心机制
AbstractQueuedSynchronizer(AQS)是 JUC 包的灵魂组件,其设计精髓在于:
- 通过 volatile int state 表示同步状态
- 内置 FIFO 等待队列管理阻塞线程
- 提供模板方法供子类实现特定同步语义
对于 ReentrantLock 而言,state 的语义非常直观:
- 0 表示锁未被任何线程持有
- 1 表示锁被独占
-
1 表示锁的重入次数
java复制// AQS 中的关键字段
private transient volatile Node head; // 队列头节点
private transient volatile Node tail; // 队列尾节点
private volatile int state; // 同步状态
2.2 CLH 队列变种实现
AQS 的等待队列是 CLH 锁的变体,其节点结构包含以下关键字段:
java复制static final class Node {
volatile int waitStatus; // 等待状态(CANCELLED/SIGNAL/CONDITION/PROPAGATE)
volatile Node prev; // 前驱节点
volatile Node next; // 后继节点
volatile Thread thread; // 等待线程
Node nextWaiter; // 条件队列链接
}
队列管理采用"懒加载"策略:
- 新节点通过 CAS 入队
- 头节点仅作为哨兵,不关联实际线程
- 取消节点会触发清理操作
3. 锁获取流程全解析
3.1 非公平锁获取流程
以默认的非公平模式为例,lock() 的完整调用链如下:
java复制// ReentrantLock.java
public void lock() {
sync.acquire(1); // 入口方法
}
// AbstractQueuedSynchronizer.java
public final void acquire(int arg) {
if (!tryAcquire(arg) && // 尝试快速获取
acquireQueued( // 加入队列等待
