tryLock() 立即返回,成功则上锁并返回true,失败立即返回false,不阻塞;带超时版本在指定时间内尝试获取,超时返回false,是防死锁关键手段。

tryLock() 不会阻塞,但默认不带超时就是立即返回
调用 tryLock() 本质是「尝试获取锁,成功就上锁并返回 true,失败就立刻返回 false」,它不会像 lock() 那样挂起线程。这点常被误认为“加锁失败会等一会儿”,其实完全不等——除非你显式传入超时参数。
常见错误现象:
- 写了 if (!lock.tryLock()) { /* 做点别的 */ } 却发现逻辑总进分支,以为锁“卡住了”,其实是当前线程根本没抢到,而其他线程正持有锁;
- 忘记在 tryLock() 返回 true 后手动 unlock(),导致锁泄漏。
使用要点:
- 必须配合
try-finally确保释放:只有tryLock()成功才需要unlock() - 不能在未持有锁时调用
unlock(),否则抛IllegalMonitorStateException - 公平锁与非公平锁下,
tryLock()行为一致(都尝试立即抢占),公平性只影响lock()的排队逻辑
带超时的 tryLock(long, TimeUnit) 是防死锁的关键手段
当你要避免线程无限等待锁,又不想直接放弃,就该用 tryLock(long timeout, TimeUnit unit)。它会在指定时间内不断尝试获取锁,超时仍未获得则返回 false。这比单纯轮询 tryLock() 更省资源,也比无条件阻塞更可控。
典型使用场景:
立即学习“Java免费学习笔记(深入)”;
- 两个资源需按顺序加锁(如转账时先锁 A 账户再锁 B),为防死锁,对第二个锁用带超时的
tryLock(),失败则释放已持锁并重试 - 实时性要求高的服务中,数据库连接池、缓存更新等操作不能卡在锁上超过 100ms
- 测试中模拟并发竞争,验证锁降级或 fallback 逻辑是否触发
注意点:
- 超时时间过短(如 1ns)可能因系统调度延迟导致几乎必然失败
- 超时判断基于纳秒精度,但实际精度受 JVM 和 OS 调度限制,不保证绝对准时
- 若线程在等待期间被中断,会抛
InterruptedException并自动放弃获取锁(不会持有锁)
tryLock() 在可重入性下的行为:同一线程可重复调用成功
ReentrantLock 是可重入的,tryLock() 也不例外。同一个线程多次调用 tryLock(),只要之前已持有该锁,后续调用都会立即返回 true,且内部计数器递增。
这意味着:
- 递归方法中安全:比如方法 A 调用自身前再次
tryLock(),不会因“已持有锁”而失败 - 但
unlock()次数必须与成功tryLock()次数匹配,否则锁无法真正释放(计数器不归零) - 若某次
tryLock()失败(返回false),不代表之前没持锁——只是这次没抢到,原有锁仍有效
ReentrantLock lock = new ReentrantLock(); lock.lock(); // 第一次获取 System.out.println(lock.tryLock()); // true —— 同一线程可重入 System.out.println(lock.getHoldCount()); // 输出 2 lock.unlock(); unlock(); // 必须解锁两次
和 synchronized 对比:tryLock() 的灵活性与代价
synchronized 完全不支持“尝试获取”语义,要么进入临界区,要么阻塞。而 tryLock() 提供了明确的控制流分支能力,适合做锁争用决策,但代价是代码更 verbose,且需人工管理锁生命周期。
性能与兼容性影响:
- 无竞争时,
tryLock()开销略高于synchronized(涉及 CAS 和队列检查) - 高竞争下,反复调用无参
tryLock()可能引发 CPU 空转,应改用带超时版本或退避策略 - Android 低版本(API ReentrantLock 支持不完整,部分设备存在唤醒延迟问题,生产环境慎用
最容易被忽略的一点:锁对象本身不是线程安全的“状态容器”。tryLock() 返回 false 只说明此刻无法获取,不代表其他线程没在操作共享数据——业务逻辑仍需自己保证一致性,比如配合 volatile 标志位或原子变量做二次校验。










