reentrantlock在非公平模式下采用先自旋后阻塞的混合策略:先cas尝试获取锁,失败后有限自旋(jvm硬编码,不可配置),再入aqs队列阻塞;公平模式跳过自旋直接入队;开发者可通过trylock或lockinterruptibly干预等待行为。

ReentrantLock 本身不直接提供“自旋锁”实现,但它在内部机制中融合了自旋与阻塞的协同策略——不是二选一,而是分阶段、按需切换。关键在于它的非公平模式下默认启用的“先自旋再阻塞”优化逻辑。
非公平模式下的自旋尝试(快速路径)
当线程调用 lock() 时,ReentrantLock 会先用 CAS 尝试一次获取锁。若失败,它不会立刻挂起线程,而是进入一个有限轮次的自旋循环(具体次数由 JVM 实现决定,通常为几十次),期间持续检查锁状态是否释放。这个过程发生在用户态,无上下文切换开销。
- 适用场景:锁持有时间极短(如毫秒级)、竞争不激烈、CPU 核心充足
- 优势:避免线程挂起/唤醒的系统调用开销,响应更快
- 注意:JDK 并未暴露自旋次数配置接口,该行为由 AQS 内部硬编码控制,不可手动调整
自旋失败后自动转入阻塞队列(慢速路径)
一旦自旋轮次耗尽仍未获取到锁,当前线程会被封装为 Node 加入 AQS 的同步队列,并调用 LockSupport.park() 进入阻塞状态。此时线程让出 CPU,不再消耗资源,等待前驱节点释放锁后被唤醒。
- 这是 ReentrantLock 的默认保底机制,确保高并发下不会因持续自旋拖垮 CPU
- 阻塞唤醒依赖底层操作系统调度,有轻微延迟,但资源友好
- 公平锁模式跳过自旋阶段,直接入队,牺牲响应速度换取调度公平性
开发者可干预的两个关键点
虽然不能改自旋次数,但你可以通过 API 主动控制线程行为:
- tryLock(long, TimeUnit):指定超时时间,内部先自旋再阻塞等待,超时则放弃,适合对响应时间敏感的业务
- lockInterruptibly():支持中断响应,阻塞中可被唤醒,避免无限等待死锁风险
- 慎用纯 lock():在已知锁竞争剧烈或临界区较长时,应优先考虑带超时的 tryLock 或降级为读写锁等更细粒度方案
实际选型建议
不必纠结“用自旋还是阻塞”,ReentrantLock 已帮你做了智能折中。真正需要你判断的是:
- 用 非公平锁(默认)发挥自旋+阻塞混合优势,适合大多数吞吐优先场景
- 用 公平锁仅当严格要求请求顺序(如任务调度器),接受性能折损
- 临界区执行时间超过 10ms?考虑拆分逻辑或换用 StampedLock / 分段锁 / 无锁结构
- CPU 使用率异常升高且锁竞争频繁?检查是否误用锁保护过大范围,而非调优自旋参数
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











