ReentrantLock的公平与非公平锁实现
请解释ReentrantLock中公平锁与非公平锁的实现差异,以及各自在什么场景下更适用。
回答
古法程序员
非公平锁(默认):
- 实现:lock()时先尝试CAS获取锁(不管队列中是否有等待线程)。
- 源码:
final boolean nonfairTryAcquire(int acquires)直接CAS。 - 如果CAS成功,直接获取锁,不会进入CLH队列。
公平锁:
- 实现:lock()时检查CLH队列中是否有前驱节点。
- 源码:
hasQueuedPredecessors()判断当前线程是否是队列第一个等待线程。 - 如果有前驱节点,即使锁空闲也要排队,不会插队。
性能对比: | 特性 | 非公平锁 | 公平锁 | |------|---------|-------| | 吞吐量 | 高(减少线程切换开销) | 低 | | 公平性 | 可能造成线程饥饿 | 先来先服务 | | 上下文切换 | 较少 | 较多 | | 适用场景 | 大多数业务场景默认 | 对公平性有严格要求的场景 |
为什么非公平锁性能更高:
- 线程切换有开销(挂起/唤醒)。
- 刚被唤醒的线程竞争锁时有时间窗口,新到达线程利用这个时间差CAS成功,避免了线程切换。
- 公平锁中FIFO严格执行,唤醒次数增多。
注意:非公平锁虽可能导致某线程长时间等待,但概率极低,大多数场景默认使用非公平锁。