reentrantlock默认是非公平锁,通过new reentrantlock(true)创建公平锁,二者构造后公平性不可更改;公平锁按fifo排队避免饥饿但吞吐低,非公平锁允许插队提升性能但可能导致线程饥饿。

ReentrantLock 默认是非公平锁,但可以通过构造函数参数显式指定为公平锁。关键区别在于线程获取锁的顺序策略:公平锁严格按等待时间先后排队,非公平锁允许新线程“插队”尝试获取锁。
如何创建公平锁与非公平锁
ReentrantLock 提供两个构造方法:
-
非公平锁(默认):
new ReentrantLock()或new ReentrantLock(false) -
公平锁:
new ReentrantLock(true)
注意:一旦创建,锁的公平性不可更改。公平性只影响 lock() 方法的行为,tryLock() 始终是非公平的(立即尝试,不排队)。
公平锁的实际表现
启用公平模式后,锁会维护一个 FIFO 等待队列。当持有锁的线程释放锁时,会唤醒队首线程,而不是让刚调用 lock() 的线程直接竞争。这能避免“饥饿”,但吞吐量通常更低。
例如:线程 A、B、C 按序调用 lock() 但未获取到锁,此时 D 进来调用 lock() —— 在公平锁下,D 必须排在 C 后面;在非公平锁下,D 可能直接抢到刚释放的锁。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
非公平锁为何是默认选择
多数场景下,非公平锁性能更好。原因包括:
- 减少线程挂起/唤醒开销(避免频繁进出队列)
- 利用 CPU 缓存局部性,刚释放锁的线程可能仍驻留缓存,再次获取成功率高
- 避免因严格排队导致的低效空转(比如前序线程被调度延迟)
除非业务明确要求响应顺序可预测(如任务调度、资源分配需强公平性),否则不建议盲目开启公平模式。
使用时的注意事项
无论公平与否,都必须配对使用 lock() 和 unlock(),推荐在 finally 块中释放:
Lock lock = new ReentrantLock(true); // 公平锁
lock.lock();
try {
// 临界区操作
} finally {
lock.unlock(); // 必须确保执行
}
另外,公平锁不能完全杜绝“假唤醒”或调度不确定性——操作系统线程调度仍可能影响实际执行顺序,公平性仅体现在锁的排队和授予逻辑层面。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










