reentrantlock的公平性由构造时选择fairsync或nonfairsync决定,运行中不可切换;非公平锁直接cas抢锁,公平锁先检查队列中是否有等待线程再尝试获取。

直接看 ReentrantLock 的构造和 lock() 方法实现,就能抓住公平与非公平的本质区别——不是锁本身不同,而是线程“抢锁”时是否愿意让排队的线程先上。
构造时就定死,运行中不可切换
ReentrantLock 只有两个构造方法:
-
ReentrantLock()→ 默认创建NonfairSync实例,即非公平锁 -
ReentrantLock(true)→ 创建FairSync实例,即公平锁
sync 是 final 字段,一旦初始化就无法更改。公平性不是开关,而是类的选择。
lock() 行为差异:插队还是排队
两者都调用 sync.lock(),但内部逻辑截然不同:
-
非公平锁(NonfairSync):第一步直接 CAS 尝试把
state从 0 改成 1;成功就立刻持有锁,完全不看队列里有没有人等着 -
公平锁(FairSync):跳过这步,直接走 AQS 的
acquire(1),并在tryAcquire中先调用hasQueuedPredecessors()—— 检查队列是否为空,或自己是不是排在最前面;只有满足才尝试 CAS
这个检查就是“守规矩”的全部含义:哪怕刚释放锁,新线程也得先看看前面有没有人,不能一上来就抢。
底层共享同一套 AQS 机制
公平和非公平锁共用:
- 相同的 CLH 队列结构、Node 节点定义
- 相同的
park()/unpark()线程挂起与唤醒逻辑 - 相同的可重入实现(靠
state计数 +exclusiveOwnerThread判断) - 相同的
unlock()流程:减 state、为 0 时唤醒后继节点
真正只改了一处:tryAcquire(int) 的实现细节。其他所有功能(中断响应、超时等待、Condition)都不受公平性影响。
怎么验证你用的是哪种?
别靠猜,看源码或调试:
- 断点进
lock(),看实际执行的是NonfairSync.lock()还是FairSync.lock() - 或者打印
lock.getClass().getSimpleName(),输出会是NonfairSync或FairSync - 注意:
tryLock()总是走非公平逻辑(调用nonfairTryAcquire),即使你用的是公平锁实例
不复杂但容易忽略











