ReentrantLock.tryLock()不会卡住是因为它是非阻塞的:调用时立即检查锁,可用则获取并返回true,不可用则立刻返回false;其两种重载分别是一次性尝试和带超时的有限尝试,使用时必须在finally中配套unlock()以避免锁泄漏。

ReentrantLock.tryLock() 为什么不会一直卡住?
因为 tryLock() 是非阻塞的:它只在调用瞬间检查锁是否可用,可用就立即获取并返回 true;不可用就立刻返回 false,绝不会挂起当前线程。这和 lock() 的“死等”行为有本质区别——后者在锁被占用时会让线程进入 WAITING 状态,直到被唤醒。
典型适用场景包括:避免线程长时间等待、实现带超时的协作逻辑、构建非阻塞算法(如无锁队列的辅助同步)、或在关键路径中快速失败而非阻塞。
tryLock() 两种重载签名的区别与选法
tryLock() 有两个常用重载:
-
tryLock():无参版本,尝试一次,成功返回true,失败立即返回false -
tryLock(long timeout, TimeUnit unit):带超时版本,在指定时间内不断尝试(底层是自旋 + 阻塞交替),超时前拿到锁则返回true,否则返回false
注意:timeout 不是“最多等这么久”,而是“总耗时不超过这个值”;内部可能经历多次短暂阻塞(如 parkNanos),但累计时间受控。超时版本仍属于“可中断”的阻塞操作,若线程在等待中被 interrupt(),会抛出 InterruptedException 并提前退出。
使用 tryLock() 必须配套 unlock(),且要放在 finally 块里
这是最容易出错的地方:tryLock() 返回 true 表示你已持有锁,但 JVM 不会自动帮你释放;一旦忘记 unlock(),就会导致锁泄漏,其他线程永远无法获取该锁。
正确写法必须是:
if (lock.tryLock()) {
try {
// 执行临界区逻辑
} finally {
lock.unlock(); // 即使抛异常也必须释放
}
} else {
// 锁不可用,走降级/重试/报错等分支
}
不能写成:
// ❌ 错误:没加 finally,异常时 unlock 不会被执行
if (lock.tryLock()) {
// 可能抛异常
doSomething();
lock.unlock(); // 这行可能根本执行不到
}
常见误用:把 tryLock() 当作“轻量版 lock()”盲目替换
直接把 lock.lock() 换成 if (!lock.tryLock()) return; 看似简单,但隐藏风险:
- 业务语义破坏:原意是“必须串行执行”,改成“抢不到就放弃”,可能引发数据不一致或请求丢失
- 忙等开销:如果在循环里高频调用无参
tryLock()(比如 while(!lock.tryLock()) Thread.yield();),会浪费 CPU - 忽略公平性影响:若
ReentrantLock是公平模式,tryLock()仍遵守队列顺序;但非公平模式下,它可能插队成功,干扰原有调度预期
真正需要的是明确设计意图:你是想“尽力而为”,还是“宁可失败也不排队”?前者考虑超时版,后者才用无参版,并配好 fallback 路径。
最常被忽略的一点是:tryLock() 的返回值必须被显式判断和响应,它不是“锁获取失败就自动重试”的魔法函数——不处理 false 分支,等于把并发问题藏得更深。

















