选trylock还是lock取决于线程能否接受等待:能等用lock,保证最终获取锁且逻辑简洁,但需try-finally确保解锁;不能等用trylock(含超时版),立即返回或限时抢占,需判返回值防临界区裸奔,超时版可防死锁并兼顾响应性。

选 tryLock 还是 lock,关键看线程是否能接受“等”——能等就用 lock,不能等或不想等就用 tryLock(含带超时版本)。两者不是性能优劣之分,而是语义和控制粒度的差异。
需要确定性同步时,用 lock()
lock() 保证最终一定能拿到锁,适合对一致性要求严格、允许阻塞的场景。它会把抢不到锁的线程挂起,进入等待队列,直到被唤醒或中断。
- 账户扣款、库存扣减这类必须串行执行的操作,用
lock()更稳妥 - 调用后无需判断返回值,逻辑更简洁;但要注意配合
try-finally确保解锁 - 若线程在等待中被中断,会抛
InterruptedException,需捕获处理
需要快速失败或限时抢占时,用 tryLock()
tryLock() 不阻塞,立即返回 true 或 false,适合做“尽力而为”的资源访问。
- 防止重复提交:用户连续点击按钮,第一次
tryLock()成功就执行,后续返回false直接忽略 - 降级兜底:比如缓存更新失败时,不卡住主线程,转而走数据库直查
- 必须检查返回值——
if (lock.tryLock()) { ... } else { ... },漏判会导致临界区裸奔
需要平衡等待与响应性时,用 tryLock(long, TimeUnit)
这是最常被低估也最实用的形态:既避免无限等待,又比轮询 tryLock() 更省资源。
- 转账操作中,先锁 A 账户,再尝试
tryLock(200, MILLISECONDS)锁 B,失败则释放 A 并重试,防死锁 - 实时接口要求 200ms 内返回,可设超时为 150ms,留出余量处理其他逻辑
- 注意单位别写错:传
TimeUnit.SECONDS却填100,实际等 100 秒而非 100 毫秒 - 等待中被中断会抛
InterruptedException,此时锁未获取成功,不可调用unlock()
锁持有与释放的守则
无论用哪个方法,释放锁都只在真正拿到锁之后发生。
-
tryLock()返回false时,绝不可调用unlock(),否则抛IllegalMonitorStateException - 推荐统一用布尔变量标记:“
boolean locked = false; if ((locked = lock.tryLock())) { ... } finally { if (locked) lock.unlock(); }” - 可重入场景下,同一线程多次
tryLock()成功,就要对应次数的unlock(),否则锁无法彻底释放
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











