ReentrantLock 默认不自旋,获取失败时直接入AQS队列并park阻塞;需手动用tryLock()配合循环实现可控自旋,避免CPU空转。

ReentrantLock 在锁获取失败时,默认不自旋,而是直接进入 AQS 队列阻塞等待;自旋行为需要手动控制,且仅在特定场景下由开发者显式启用(如使用 tryLock(long, TimeUnit) 或配合自定义逻辑)。
ReentrantLock 默认不自旋,依赖 AQS 的阻塞机制
与 synchronized 不同,ReentrantLock 底层基于 AbstractQueuedSynchronizer(AQS)。当线程调用 lock() 但无法立即获取锁时,AQS 会将该线程封装为 Node 加入同步队列,并调用 LockSupport.park() 将其挂起——这是阻塞式等待,不是 CPU 自旋。
- 没有内置的忙等待(busy-wait)或自旋重试逻辑
- 避免无谓消耗 CPU,适合临界区较长或竞争较激烈的场景
- 唤醒依赖锁释放时的 unpark,由 AQS 保证 FIFO 和公平性(若启用公平模式)
想实现自旋,需手动配合 tryLock + 循环重试
若业务希望在锁短暂不可用时“等一会儿再试”,可借助 tryLock() 方法构建带超时/次数限制的自旋逻辑:
-
tryLock()立即返回 boolean,成功则获得锁,失败则不阻塞 - 配合 while 循环和短暂停顿(如
Thread.yield()或LockSupport.parkNanos(100)),模拟轻量级自旋 - 注意设置最大尝试次数或总耗时上限,防止无限自旋导致线程饥饿
示例片段:
立即学习“Java免费学习笔记(深入)”;
boolean acquired = false;for (int i = 0; i if (lock.tryLock()) {
acquired = true;
break;
}
Thread.yield(); // 或 parkNanos(50) 控制自旋强度
}
if (!acquired) {
// 转为阻塞式获取,或降级处理
lock.lock();
}
公平锁与非公平锁对“获取失败”的影响不同
非公平模式下,新线程可能插队成功(即刚调用 lock() 就抢到锁),这看似像“自旋收益”,实则是 CAS 抢占,不是真正自旋;公平模式则严格排队,新请求一律入队,基本不会出现插队。
- 非公平锁:可能减少部分线程的排队时间,但不改变“获取失败即入队”的本质
- 公平锁:所有失败请求都走完整入队流程,响应延迟更可预测,但吞吐通常略低
- 二者都不主动自旋,区别在于是否允许新请求绕过队列尝试抢占
真正需要自旋时,应优先考虑其他工具
若临界区极短(纳秒~微秒级)、竞争极少,且 CPU 资源充裕,可考虑更底层的自旋控制:
-
java.util.concurrent.atomic类(如 AtomicInteger)——无锁、CAS 自旋,由 JVM 优化 - 显式使用
Unsafe.compareAndSwapInt+ 手动自旋循环(难度高,一般不推荐) - 第三方库如 Chronicle-Bytes 提供的低延迟自旋锁(非 JDK 标准)
- ReentrantLock 的设计目标是通用性和可重入性,不是低延迟自旋


















