news 2026/10/14 5:09:19

【JUC】公平锁与非公平锁

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【JUC】公平锁与非公平锁

在 Java 多线程中,公平锁和非公平锁是ReentrantLock提供的两种锁获取策略,核心区别在于:多个线程竞争锁时,是否严格按照“先来后到”的顺序获取锁。

下面从原理、实现、优缺点和代码示例几个方面来讲。


一、基本概念

1. 公平锁(Fair Lock)

  • 多个线程按照申请锁的顺序来获取锁,先到先得。
  • 线程会进入一个 FIFO 队列排队,只有队首的线程才能获取锁。
  • 新来的线程不能插队,即使锁刚好空闲,也要先看队列里有没有等待的线程。

2. 非公平锁(Nonfair Lock)

  • 不保证顺序,允许插队。
  • 新来的线程可以直接尝试 CAS 抢锁,如果抢到了就直接执行,不管队列里有没有等待的线程。
  • 抢不到再进入队列等待。

二、源码层面的区别

ReentrantLock内部通过Sync抽象类实现,有两个子类:

publicclassReentrantLockimplementsLock{privatefinalSyncsync;abstractstaticclassSyncextendsAbstractQueuedSynchronizer{// ...}// 非公平锁staticfinalclassNonfairSyncextendsSync{...}// 公平锁staticfinalclassFairSyncextendsSync{...}}

非公平锁的加锁逻辑(简化)

finalvoidlock(){// 直接 CAS 抢锁,不管有没有队列if(compareAndSetState(0,1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);// 抢不到再走正常流程}

tryAcquire中也不会检查队列:

protectedfinalbooleantryAcquire(intacquires){returnnonfairTryAcquire(acquires);}

公平锁的加锁逻辑

protectedfinalbooleantryAcquire(intacquires){finalThreadcurrent=Thread.currentThread();intc=getState();if(c==0){// 关键:先判断队列中是否有前驱节点if(!hasQueuedPredecessors()&&compareAndSetState(0,acquires)){setExclusiveOwnerThread(current);returntrue;}}// ... 可重入逻辑}

hasQueuedPredecessors()是公平锁的核心:如果队列里已经有线程在等,就不抢,乖乖排队。


三、公平锁 vs 非公平锁对比

维度公平锁非公平锁
获取顺序严格 FIFO允许插队
吞吐量较低较高
线程饥饿不会可能(理论上)
上下文切换较多较少
实现复杂度略高略低
默认策略否是(ReentrantLock 默认非公平)

为什么非公平锁吞吐量更高?

因为公平锁每次都要唤醒队首线程,涉及线程切换(用户态→内核态),开销大。而非公平锁允许刚释放锁的线程或新来的线程立刻抢到锁,减少了线程唤醒和切换的次数。

注意:非公平锁虽然可能“插队”,但一旦进入队列,仍然是 FIFO 的,只是新来的线程有机会在入队前抢到锁。


四、代码示例

importjava.util.concurrent.locks.ReentrantLock;publicclassFairLockDemo{// true 表示公平锁,false 表示非公平锁privatestaticfinalReentrantLockfairLock=newReentrantLock(true);privatestaticfinalReentrantLockunfairLock=newReentrantLock(false);publicstaticvoidmain(String[]args){testLock(fairLock,"公平锁");System.out.println("----------");testLock(unfairLock,"非公平锁");}privatestaticvoidtestLock(ReentrantLocklock,Stringname){Runnabletask=()->{for(inti=0;i<2;i++){lock.lock();try{System.out.println(name+" -> "+Thread.currentThread().getName()+" 获取锁");}finally{lock.unlock();}}};for(inti=0;i<5;i++){newThread(task,"线程-"+i).start();}try{Thread.sleep(1000);}catch(InterruptedExceptione){}}}

公平锁下,输出顺序基本是线程-0、线程-1、线程-2...轮转;非公平锁下顺序可能混乱,某些线程会连续获取多次。


五、其他相关点

1. synchronized 是公平锁吗?

不是。synchronized是非公平的,且不支持设置为公平锁。它的锁获取策略由 JVM 实现,偏向锁、轻量级锁、重量级锁都偏向于性能,不保证公平。

2. 读写锁的公平性

ReentrantReadWriteLock也支持公平/非公平:

newReentrantReadWriteLock(true);// 公平

3. 什么时候用公平锁?

  • 业务要求严格按顺序执行,比如某些资源调度。
  • 需要避免线程饥饿的场景。
  • 大多数情况下,优先用非公平锁(默认),性能更好。

六、一句话总结

公平锁按排队顺序获取锁,避免饥饿但性能较低;非公平锁允许插队,吞吐量高但可能造成线程饥饿。ReentrantLock默认是非公平锁,通过构造函数new ReentrantLock(true)可开启公平模式。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 5:08:48

MiniMax H3 4-bit量化部署实战指南

1. 项目概述&#xff1a;为什么4-bit量化是H3模型在消费级显卡上真正落地的关键最近在ComfyUI社区里&#xff0c;几乎每天都能看到新用户发帖问&#xff1a;“RTX 3060能跑MiniMax H3吗&#xff1f;”“我的GTX 1660 Super装完就OOM”“秋叶包里选了H3但加载失败&#xff0c;日…

作者头像 李华
网站建设 2026/10/14 5:08:40

Spring Boot商场停车场预约服务管理信息系统设计与实现

工作日早高峰的商场停车场&#xff0c;入口排长队、地库转圈找车位——这个场景我相信每个开车去商圈的人都经历过。问题本质就两个&#xff1a;入口车道吞吐量不够&#xff0c;场内车位信息不透明。车主不知道哪有空位&#xff0c;只能漫无目的地转&#xff1b;管理方不知道谁…

作者头像 李华
网站建设 2026/10/14 5:08:38

家庭近视防控:科学护眼从日常做起

1. 近视防控的家庭实践意义近视问题已经成为困扰当代青少年健康发展的主要视力障碍之一。根据临床观察&#xff0c;近视发展呈现明显的低龄化趋势&#xff0c;许多儿童在学龄前就已出现视力问题。作为家长&#xff0c;我们常常陷入一个误区——认为近视防控只是医疗机构的责任&…

作者头像 李华
网站建设 2026/10/14 5:08:24

合作博弈在园区综合能源系统优化调度与利益分配中的Matlab实现

去年我在复现一个综合能源系统的优化调度项目&#xff0c;正好卡在一个特别现实的问题上&#xff1a;园区里风电场、光伏电站、燃气轮机和储能电池分属不同的运营主体&#xff0c;各自单独算账时&#xff0c;燃气机组要为风光波动频繁调峰&#xff0c;成本高得吓人&#xff1b;…

作者头像 李华
网站建设 2026/10/14 5:08:19

第四次作业全攻略:从练习到项目,掌握这几点轻松过关

1. 第四次作业&#xff1a;为什么它总是一道分水岭如果你正在为“第四次作业”发愁&#xff0c;先别急着怀疑自己。我常年接触各类课程作业和项目评审&#xff0c;见过太多人前三次作业轻松拿高分&#xff0c;第四次却连续熬夜还交不出一份满意的结果。原因并不一定是题目变难了…

作者头像 李华
网站建设 2026/10/14 5:08:10

IT自动化运维平台建设实战:从CMDB到作业编排的落地方法论

简介&#xff1a;这份PPT是面向IT运维团队与技术管理者的自动化运维平台建设方案&#xff0c;内容系统梳理了从人工运维、自动化运维到智能化运维的演进路径&#xff0c;并给出可落地的总体规划。方案围绕数据整合、任务调度、智能监控、自动运维、风险诊断五个重点阶段展开&am…

作者头像 李华