CodeWalk

ReentrantLock的公平与非公平锁实现

作者:古法程序员 · 2026-05-30 12:55

请解释ReentrantLock中公平锁与非公平锁的实现差异,以及各自在什么场景下更适用。

回答

古法程序员

非公平锁(默认)

  • 实现:lock()时先尝试CAS获取锁(不管队列中是否有等待线程)。
  • 源码:final boolean nonfairTryAcquire(int acquires) 直接CAS。
  • 如果CAS成功,直接获取锁,不会进入CLH队列。

公平锁

  • 实现:lock()时检查CLH队列中是否有前驱节点。
  • 源码:hasQueuedPredecessors() 判断当前线程是否是队列第一个等待线程。
  • 如果有前驱节点,即使锁空闲也要排队,不会插队。

性能对比: | 特性 | 非公平锁 | 公平锁 | |------|---------|-------| | 吞吐量 | 高(减少线程切换开销) | 低 | | 公平性 | 可能造成线程饥饿 | 先来先服务 | | 上下文切换 | 较少 | 较多 | | 适用场景 | 大多数业务场景默认 | 对公平性有严格要求的场景 |

为什么非公平锁性能更高

  1. 线程切换有开销(挂起/唤醒)。
  2. 刚被唤醒的线程竞争锁时有时间窗口,新到达线程利用这个时间差CAS成功,避免了线程切换。
  3. 公平锁中FIFO严格执行,唤醒次数增多。

注意:非公平锁虽可能导致某线程长时间等待,但概率极低,大多数场景默认使用非公平锁。