reentrantlock 依赖 cpu 原子指令(如 x86 的 lock cmpxchg)、volatile 语义及内存屏障、os 原语(如 futex)三层协同实现高效同步,不依赖 jvm 的 monitorenter/monitorexit。

ReentrantLock 的同步机制不依赖 JVM 层面的 monitorenter/monitorexit 字节码,而是基于 Unsafe 类提供的 CAS(Compare-And-Swap)原子操作,最终映射到 CPU 级别的原子指令(如 x86 上的 LOCK CMPXCHG),配合 volatile 语义实现锁状态的线程安全更新与可见性保障。
CAS 操作对应底层 CPU 指令
ReentrantLock 的核心是 AQS(AbstractQueuedSynchronizer)中对 state 字段的原子修改。AQS 使用 Unsafe.compareAndSwapInt 尝试更新 state 值:
- 在 x86 架构下,JVM 会将该调用编译为带
LOCK前缀的CMPXCHG指令(如lock cmpxchg %eax,(%rdx)); -
LOCK前缀确保该指令执行期间独占总线或缓存行,使 CAS 具备原子性; - ARM 架构则对应
LDXR/STXR或SWP类指令,由硬件保证原子读-改-写。
volatile 字段提供内存可见性保障
AQS 中的 state、head、tail 等字段均声明为 volatile:
- 写 volatile 变量会插入 StoreStore 和 StoreLoad 内存屏障,禁止重排序,并强制刷新到主内存;
- 读 volatile 变量会插入 LoadLoad 和 LoadStore 屏障,确保后续读取能看到最新值;
- 这些屏障在 CPU 层面对应
mfence(x86)、dsb sy(ARM)等指令,协同 CAS 实现“获取-释放”语义。
线程挂起与唤醒依赖操作系统原语
当 CAS 失败且需排队时,AQS 调用 LockSupport.park() 阻塞线程:
- park 底层调用 OS 的线程调度接口(如 Linux 的
futex_wait); - futex 是用户态+内核态结合的轻量同步机制,仅在竞争激烈时陷入内核;
- unlock 时通过
futex_wake唤醒等待线程,避免无谓的上下文切换。
公平锁额外引入队列检查逻辑
公平模式下,acquire 流程在 CAS 前多一步:检查同步队列是否有前驱节点(即是否有人先排队):
- 该判断本身不涉及 CPU 特殊指令,但依赖 volatile 读取
head/tail和节点prev引用; - 真正影响性能的是额外的链表遍历开销和更频繁的 park/unpark,而非指令级差异;
- 不公平锁省略此检查,允许新线程直接 CAS 抢占,体现为更高的吞吐量和更差的等待公平性。
ReentrantLock 的高效性正来自这种分层设计:CPU 原子指令保障状态变更的原子性,volatile 与内存屏障保障跨核可见性,OS 原语处理阻塞调度——三者协同,绕过传统 monitor 的重量级锁机制。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











