摘要
synchronized
的底层并不仅仅停留在字节码和对象头,它最终依赖操作系统的互斥量(mutex)来实现线程的阻塞与唤醒。本文将详细解析 synchronized 与 OS 层互斥机制的联系,揭示从 JVM 到内核的完整锁实现链路。
一、引言
我们在前一篇文章中,已经从 字节码与 Monitor 的角度理解了 synchronized
。
但有一个关键问题还没有解答:
👉 monitorenter
和 monitorexit
是 JVM 指令,那它们最终如何落实到硬件层面?
答案就是:依赖操作系统提供的互斥量(mutex)机制。
也就是说,synchronized
从源码到运行的路径是:
Java 代码 → JVM 字节码 → Monitor → OS 互斥量 → CPU 硬件原子指令
二、为什么需要操作系统的支持?
在单核 CPU 时代,我们或许只需要简单的"关闭中断"就能实现互斥。但在现代多核 CPU + 多线程并发场景下,仅靠 JVM 内部逻辑无法解决所有问题:
- 上下文切换:当线程无法获得锁时,需要进入阻塞状态并等待调度。
- 线程唤醒:锁释放时,需要操作系统将等待的线程重新唤醒。
- 跨 CPU 同步:不同 CPU 核心需要通过总线锁、缓存一致性协议来保证正确性。
这些操作超出了 JVM 的能力范围,因此必须依赖 操作系统内核提供的互斥原语。
三、JVM Monitor 与操作系统互斥量
在 HotSpot 虚拟机中,synchronized
的实现依赖于 ObjectMonitor。
当线程竞争激烈、轻量级优化失效时,ObjectMonitor 会退化为依赖操作系统的 mutex/condition 机制。
以 Linux 平台 为例,HotSpot 中 ObjectMonitor 的底层实现依赖:
- pthread_mutex_t(互斥量):保证只有一个线程能进入临界区。
- pthread_cond_t (条件变量):配合
wait/notify
实现线程挂起与唤醒。
换句话说:
monitorenter
→ 对应 pthread_mutex_lock()monitorexit
→ 对应 pthread_mutex_unlock()Object.wait()
/Object.notify()
→ 对应 pthread_cond_wait() / pthread_cond_signal()
四、加锁路径解析
我们用一个流程来梳理 synchronized 与 OS mutex 的关系:
1. 快速路径:用户态自旋
- 首先尝试 CAS(Compare-And-Swap) 修改对象头的 Mark Word。
- 如果成功,则不涉及操作系统调用(用户态完成加锁)。
2. 失败路径:进入阻塞
- 如果 CAS 多次失败(说明竞争激烈),JVM 会将线程挂起。
- 这时会调用 pthread_mutex_lock ,线程进入 内核态,由操作系统接管调度。
- 等待唤醒后,再次尝试获取锁。
3. 解锁路径
monitorexit
时,如果有线程等待,则通过 pthread_mutex_unlock + pthread_cond_signal 唤醒。- 唤醒的线程由操作系统调度,重新进入就绪队列。
这就是 用户态 → 内核态 的锁获取完整链路。
五、内核态切换的开销
调用操作系统互斥量意味着发生 用户态 → 内核态切换,其开销比单纯的 CAS 要大很多。
- CAS 自旋:几十纳秒级别。
- 内核阻塞/唤醒:可能需要微秒甚至毫秒。
因此 JVM 在设计 synchronized 时,采取了 锁优化策略:
- 偏向锁 ------ 在无竞争时,几乎零开销。
- 轻量级锁 ------ 通过 CAS 和自旋解决短时间竞争。
- 重量级锁 ------ 竞争严重时,才退化为依赖 OS mutex。
这种分层机制,最大化地减少了进入内核态的次数。
六、与 CPU 指令的联系
操作系统的互斥量,最终也是依赖 CPU 的原子指令实现的,比如:
- x86 架构 :
lock cmpxchg
、xchg
- ARM 架构 :
LDREX/STREX
这些硬件指令能在总线上加锁,保证多核 CPU 下的原子性。
所以完整链路是:
synchronized → JVM Monitor → pthread_mutex → 内核调度 → CPU 原子指令
七、直观流程图
我们用 Mermaid 图画出 synchronized 与 OS 互斥量的联系:

八、总结
synchronized
底层依赖 JVM Monitor,而 Monitor 在竞争激烈时会调用操作系统的 互斥量(mutex) 。monitorenter/monitorexit
→ 映射到 pthread_mutex_lock/unlock,保证线程互斥。wait/notify
→ 对应 pthread_cond_wait/signal,实现线程等待和唤醒。- 为减少内核切换开销,JVM 采用 偏向锁、轻量级锁、重量级锁 分层优化。
- 最终所有锁的实现都依赖 CPU 原子指令 来保障并发正确性。