ReentrantLock默认是非公平锁,启用公平锁需显式传true;公平锁按FIFO排队但吞吐低、延迟高,非公平锁允许插队且性能更好,适用场景需权衡。

ReentrantLock 构造时怎么选公平模式
默认是非公平锁,要启用公平锁必须显式传 true 给构造函数。不传或传 false 都是非公平——这点容易被误以为“不传就是公平”。
-
new ReentrantLock()→ 非公平(等价于new ReentrantLock(false)) -
new ReentrantLock(true)→ 公平,线程按等待顺序获取锁
公平模式下,新来的线程不会插队,但会带来额外开销:每次加锁都要检查同步队列是否为空、是否有前驱节点,还要维护 FIFO 队列结构。
公平锁在高竞争下反而可能降低吞吐量
非公平锁允许刚释放锁的线程立刻重入(即“唤醒后直接抢”),减少了上下文切换和线程阻塞;而公平锁强制排队,即使持有锁的线程刚释放,下一个线程也得等前面所有等待者轮完。
- 低竞争场景(如锁很少争用):公平/非公平差异不明显
- 高竞争场景(如多线程频繁进出临界区):非公平锁通常吞吐更高,延迟更稳定
- 公平锁适合对响应时间敏感且需可预测调度的场景(如实时任务、调试环境)
实测中,开启公平锁后,在 20+ 线程争用同一把锁时,平均获取延迟可能上升 3–5 倍,吞吐下降约 30%~40%。
立即学习“Java免费学习笔记(深入)”;
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
如何验证当前锁是否启用公平模式
没有公开 API 直接返回“是否公平”,但可通过反射读取 sync 字段的实现类名判断:
Field syncField = ReentrantLock.class.getDeclaredField("sync");
syncField.setAccessible(true);
Object sync = syncField.get(lock);
boolean isFair = sync.getClass().getName().contains("FairSync");
不过这属于内部实现细节,不同 JDK 版本类名可能变化(如 FairSync / NonfairSync),生产环境不建议依赖。更稳妥的方式是:自己封装一个带标记的子类,或在创建时记录配置。
tryLock(long, TimeUnit) 在公平锁下仍可能失败
即使启用了公平模式,tryLock(100, TimeUnit.MILLISECONDS) 也不是“保证最多等 100ms 后一定拿到锁”,而是“最多阻塞 100ms,期间若未获得锁就返回 false”。公平性只影响排队顺序,不影响超时逻辑本身。
- 公平锁下,该线程仍需排在队列尾部,前面有 5 个等待者?那它大概率超时失败
- 非公平锁下,它还有机会在锁释放瞬间“插队成功”,成功率略高
- 无论哪种模式,
tryLock()(无参)都**不遵守公平性**,永远是非公平尝试
真正需要强公平保障的业务逻辑,不能只靠 tryLock + 超时,得配合循环重试或降级策略,否则容易在压力下大量失败。
true。

















