本质区别在于线程是否“先看队列再动手”:公平锁强制排队后按序尝试,非公平锁允许新线程跳过队列直接抢占;二者仅在aqs的tryacquire逻辑分支有异,公平版开头校验hasqueuedpredecessors(),非公平版直行cas。

本质区别在于线程是否“先看队列再动手”——公平锁强制排队后按序尝试,非公平锁允许新线程跳过队列、直接抢占。
公平锁:严格守序,入队即锁定顺序
启用公平模式(如 new ReentrantLock(true) 或 new Semaphore(permits, true))后,任何线程调用 lock() 或 acquire() 时,AQS 都会先执行 hasQueuedPredecessors() 判断:只要等待队列中存在更早排队的节点,就立即放弃 CAS 尝试,直接入队。
- 所有请求线程无一例外进入 CLH 同步队列,按到达时间严格 FIFO 排序
- 释放锁(
unlock()或release())时只唤醒队首线程,不跳过任何等待者 - 即使刚释放锁、state 恢复为可用,新线程也不能绕过队列——它必须排到队尾
非公平锁:先抢后等,抢占失败才排队
默认行为(new ReentrantLock() 或 new Semaphore(permits))下,线程首次尝试获取锁时,会跳过队列检查,直接执行 CAS 修改 state。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 只要当前锁空闲(state == 0 且无人持有),新线程就能立刻成功获取,完全不关心队列里有没有人等着
- 只有 CAS 失败(state > 0 或已被占用),才转入 AQS 标准流程:入队、挂起、等待唤醒
- 释放锁后唤醒队首,但此时若有新线程同时发起请求,它仍可再次抢占——造成“后来者居上”
关键差异落在 AQS 的 tryAcquire 实现分支
两种模式共用同一套 AQS 框架,区别仅在 tryAcquireShared(Semaphore)或 tryAcquire(ReentrantLock)的逻辑分叉:
- 公平版:开头强制校验
!hasQueuedPredecessors(),为 false 就返回失败,不给 CAS 机会 - 非公平版:省略该判断,直奔
compareAndSetState(0, 1)或类似操作,抢到了就算数
这个微小的 if 分支,决定了调度是“守序型”还是“机会型”——不是锁本身是否公平,而是许可或锁资源的分配决策是否尊重时间先后。
注意:公平性不等于执行优先级或响应及时性
公平锁只保证请求顺序被尊重,不干预 CPU 调度、不加速 IO、也不缓解业务阻塞。若某线程持锁时间过长,后续所有线程仍需等待;饥饿风险虽低,但超时控制(如 tryLock(long, TimeUnit))、队列长度监控等仍需配套使用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










