java中reentrantlock非公平锁通过cas操作state字段实现,先直接尝试抢锁再入队,配合volatile保证可见性,提升吞吐量但存在轻微饥饿风险。

Java 中 ReentrantLock 的非公平锁实现,其核心原子操作依赖于 Unsafe.compareAndSwapInt(CAS),配合 AQS(AbstractQueuedSynchronizer)的 state 字段完成锁状态的无锁更新。
非公平锁的 tryAcquire 是关键入口
非公平锁在调用 lock() 时,会直接尝试一次 CAS 获取锁,不检查同步队列是否有等待线程——这就是“非公平”的体现。该逻辑封装在 NonfairSync.tryAcquire(int acquires) 中:
- 先通过
getState()读取当前锁状态(0 表示空闲,>0 表示已被持有) - 若状态为 0,则执行
compareAndSwapInt(this, stateOffset, 0, 1)尝试将 state 从 0 改为 1 - 若 CAS 成功,说明抢锁成功,设置当前线程为独占线程(
setExclusiveOwnerThread(Thread.currentThread())) - 若 state 不为 0,还需判断是否是重入:如果是当前线程持有锁,就直接递增 state(无需 CAS)
CAS 操作本身是 JVM 层的原子指令
Unsafe.compareAndSwapInt 在 HotSpot 中最终映射为 CPU 的 cmpxchg 指令(x86 平台),该指令由硬件保证原子性:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 它一次性完成“读-比较-写”三个动作,不可中断
- 仅当内存地址处的值等于预期值(expect)时,才写入新值(update),并返回是否成功
- 即使多个线程并发执行同一 CAS,也只有一个能成功,其余失败后需退回到 AQS 的 acquire 流程(入队、挂起等)
state 字段的 volatile 语义保障可见性
AQS.state 被声明为 volatile int,这带来两层作用:
- 确保每次读取
getState()都从主内存加载最新值,避免线程本地缓存导致的状态不一致 - 配合 CAS 操作,形成“读-改-写”过程中的 happens-before 关系,使锁获取/释放的内存效应对其他线程可见
- 注意:CAS 本身不依赖 volatile 保证原子性,但 volatile 是正确同步所必需的可见性基础
非公平性不等于“随机”,而是“插队优先”
非公平锁不是放弃排队,而是在加锁入口多了一次“插队式” CAS 尝试:
- 刚调用
lock()的线程会先抢一次,成功则跳过队列;失败才走标准 AQS 入队流程 - 已排队的线程仍按 FIFO 顺序被唤醒,非公平性只体现在新请求与队首节点的竞争上
- 这种设计减少线程上下文切换,提升吞吐量,但也可能造成饥饿(不过实践中极少发生)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










