ReentrantLock 通过分段锁、精简临界区、tryLock 和读写分离等策略缓解竞争损耗。具体包括:按资源分段配独立锁;锁只护关键路径,移出远程调用等耗时操作;用 tryLock 避免死等;读多写少时选用 ReentrantReadWriteLock 或 StampedLock。

ReentrantLock 本身不消除竞争,而是提供更精细的控制手段来缓解竞争带来的性能损耗。关键不在“用不用锁”,而在“怎么用锁”——通过降低争用概率、缩短阻塞时间、避免无谓等待,把损耗压到最低。
按资源分段,让线程各锁各的
多个线程抢同一把锁,是性能损耗的主因。解决办法是把大资源拆开,每段配独立锁:
- 比如缓存有 100 个桶,就创建 100 个 ReentrantLock 实例,用 key.hashCode() % 100 映射到对应锁
- 商品库存按 SKU 分片,每个 SKU 使用专属锁实例,不同商品操作完全不冲突
- 避免“一个 ReentrantLock 全局共用”的反模式,那只是把 synchronized 换了个写法而已
锁只护关键路径,绝不拖泥带水
持有锁的时间越长,其他线程排队越久,上下文切换越多。必须把非必要逻辑移出临界区:
- 远程调用、日志打印、JSON 序列化、耗时计算等,一律放在 lock/unlock 之外
- 先在锁内读取/更新核心字段,解锁后再做校验、通知、审计等后续动作
- 示例:扣库存只在锁内改数据库字段或内存计数器,订单创建、消息发送都放外面
用 tryLock 避免死等,主动放弃比空转更高效
当锁被占时,传统 lock() 会让线程挂起再唤醒,开销大;tryLock 可设超时或立即返回,把控制权交还给业务:
立即学习“Java免费学习笔记(深入)”;
- tryLock(100, TimeUnit.MILLISECONDS):最多等 100ms,超时就走降级逻辑(如返回库存不足、触发重试)
- tryLock():纯非阻塞,适合高频读+低频写的场景,失败立刻重试或跳过
- 注意捕获 InterruptedException,并恢复线程中断状态:Thread.currentThread().interrupt()
选对锁类型,读多写少就别硬扛排它锁
如果读操作远多于写操作(比如配置中心、用户权限缓存),ReentrantLock 的排它特性反而成了瓶颈:
- 优先考虑 ReentrantReadWriteLock:允许多个读线程并发,写线程独占
- 更高阶可选 StampedLock:支持乐观读,读时不加锁,仅在验证版本号时才可能升级,吞吐量更高
- synchronized 或 ReentrantLock 全局排它,在纯读场景下属于过度保护



















