400 8949 560

NEWS/新闻

分享你我感悟

您当前位置> 主页 > 新闻 > 技术开发

Java并发编程中公平锁和非公平锁区别_锁策略说明

发表时间:2025-12-31 00:00:00

文章作者:P粉602998670

浏览次数:

公平锁严格按等待顺序分配锁,非公平锁允许新线程抢占;前者吞吐低但保证FIFO,后者性能高但可能饥饿;tryLock()始终非公平;Synchronized默认非公平且不可配。

公平锁会严格按等待顺序分配锁,非公平锁允许插队

公平锁(ReentrantLock(true))让线程排队获取锁,先调用 lock() 的线程优先获得;非公平锁(ReentrantLock(false),也是默认构造)允许刚唤醒或新来的线程直接尝试抢占锁,哪怕队列里已有等待者。这不是“随机”,而是基于 CAS 快速抢锁的机制——只要当前锁空闲,就可能被新线程抢走。

非公平锁吞吐量更高,但可能引发线程饥饿

非公平锁减少线程挂起/唤醒开销,在高竞争场景下平均吞吐更高;公平锁因强制排队,上下文切换更频繁,性能通常低 10%–30%。但要注意:如果写线程持续高频抢锁,读线程可能长期得不到机会,尤其在单核或锁持有时间长的场景下,Thread.isInterrupted() 或超时机制也救不了它。

公平锁的 tryLock() 行为和非公平锁一致

无论是否公平,tryLock() 都是立即尝试、不排队、不阻塞。它底层调用的是非公平路径的 CAS 尝试,所以:

  • ReentrantLock(true).tryLock() 仍可能跳过队首线程
  • 想真正“按序尝试”,得用 tryLock(long, TimeUnit) 配合自定义排队逻辑
  • 公平性只体现在 lock() 和条件队列唤醒上

实际选型:默认用非公平,仅当业务强依赖 FIFO 时才切公平

多数业务不需要绝对顺序,比如缓存更新、日志写入、计数器累加,非公平锁已足够健壮;只有类似资源池分配、任务调度队列、银行账户扣款等明确要求“先到先服务”的场景,才值得承担性能损失启用公平模式。另外注意:Synchronized 本质是非公平的,且不可配置。

立即学习“Java免费学习笔记(深入)”;

ReentrantLock fairLock = new ReentrantLock(true);   // 公平
ReentrantLock unfairLock = new ReentrantLock();     // 非公平(等价于 new ReentrantLock(false))

公平性开关一旦创建就不能改,而且它只影响锁获取逻辑,不影响重入、条件变量或中断响应行为。最容易被忽略的是:即使开了公平锁,如果线程在 await() 后被唤醒,再调用 lock() 时仍要重新排队——不是“唤醒即得锁”。

相关案例查看更多