ReentrantLock 是 Java 中基于 AQS 实现的可重入显式锁,支持公平/非公平策略、可中断等待、超时获取及条件变量;通过 state 和 exclusiveOwnerThread 实现重入,需手动 lock/unlock 且 unlock 必在 finally 块中。

ReentrantLock 是 Java 中一个可重入的显式锁,比 synchronized 更灵活,支持公平/非公平策略、可中断等待、超时获取、条件变量等特性。它实现“可重入”的核心在于内部通过 AQS(AbstractQueuedSynchronizer)维护一个 state 状态值 和一个 exclusiveOwnerThread 持有线程引用,同一线程多次调用 lock() 时,state 自增,unlock() 时自减,直到归零才真正释放锁。
基本用法:手动加锁与解锁
使用 ReentrantLock 必须显式调用 lock() 加锁、unlock() 解锁,且 unlock() 必须放在 finally 块中,防止因异常导致锁未释放而死锁。
- 创建锁对象:
ReentrantLock lock = new ReentrantLock();(默认非公平) - 加锁:
lock.lock();—— 阻塞直到获取成功 - 解锁:
lock.unlock();—— 必须与 lock() 成对出现,且由同一线程调用
示例:
ReentrantLock lock = new ReentrantLock();
public void doSomething() {
lock.lock();
try {
// 临界区逻辑(可安全重入)
methodA();
} finally {
lock.unlock(); // 关键:确保释放
}
}
private void methodA() {
lock.lock(); // 同一线程可再次获取,state 变为 2
try {
// ...
} finally {
lock.unlock(); // state 减为 1
}
}
判断是否可重入:利用 isHeldByCurrentThread() 和 getHoldCount()
ReentrantLock 提供了两个实用方法验证可重入行为:
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
-
lock.isHeldByCurrentThread():当前线程是否持有该锁 -
lock.getHoldCount():当前线程对该锁的持有次数(即重入深度)
例如在递归或嵌套调用中,可通过 getHoldCount() 判断是否首次进入临界区,避免重复初始化。
可选配置:公平锁 vs 非公平锁
构造时传入 true 可启用公平模式:new ReentrantLock(true)。
- 非公平锁(默认):允许新线程“插队”尝试获取锁,吞吐量高,但可能产生线程饥饿
- 公平锁:按等待顺序分配锁,更“公正”,但上下文切换开销大、性能略低
注意:公平性只影响 阻塞后排队的线程,不阻止刚唤醒的线程和新来的线程竞争(公平锁下新线程仍需排队)。
进阶能力:tryLock、lockInterruptibly、newCondition
相比 synchronized,ReentrantLock 支持更多控制方式:
-
tryLock():非阻塞尝试获取锁,立即返回 boolean -
tryLock(long, TimeUnit):带超时的尝试获取,避免无限等待 -
lockInterruptibly():可响应中断的加锁,被 interrupt() 时抛出 InterruptedException -
lock.newCondition():创建绑定到该锁的 Condition 实例,实现精准唤醒(类似 Object 的 wait/notify,但更可控)
这些能力让 ReentrantLock 在复杂并发场景(如实现阻塞队列、信号量、自定义同步器)中更具优势。

















