Java的synchronized对应的Monitor是什么
🚩 synchronized 的基本概念
在 Java 中,synchronized 是一种 内置锁(Monitor锁) 的实现,任何对象都天然可以作为锁(因为每个对象都拥有一份与之关联的 Monitor 数据结构)。
synchronized 可以用于:
- 修饰实例方法(锁当前对象)
 - 修饰静态方法(锁类对象 
Class) - 修饰代码块(锁指定对象)
 
🚩 字节码层面的实现
当您编译一个包含 synchronized 的 Java 类,javap 可以看到生成的 JVM 指令:
例如:
public void foo() {
    synchronized(this) {
        // critical section
    }
}
用 javap -c 查看字节码:
monitorenter
...
monitorexit
▶ 关键字节码指令
monitorenter:线程试图获取对象监视器(Monitor)monitorexit:线程释放对象监视器(Monitor)
👉 每个对象在 JVM 中都有一个 对象头(Object Header),其中包含指向监视器的引用或锁状态信息。
🚩 JVM 对象模型与对象头结构
HotSpot 的对象头大致结构(32位模式):
| Mark Word (32 bits) |
| Klass Pointer (32 bits) |
64位模式下 Mark Word 是 64 bits。
Mark Word 存储的信息(取决于对象状态)
| 状态 | Mark Word 内容 | 
|---|---|
| 无锁 | 哈希码、GC 分代信息、偏向线程 ID 等 | 
| 偏向锁 | 偏向线程 ID、时间戳 | 
| 轻量级锁 | 指向栈中 Lock Record 的指针 | 
| 重量级锁 | 指向 Monitor 对象的指针 | 
| GC 标记 | GC 状态信息 | 
👉 Mark Word 就是锁状态的关键位置
🚩 锁的实现机制
synchronized 底层主要由以下几种锁状态驱动实现:
1️⃣ 偏向锁 (Biased Locking)
- 如果对象第一次被某线程获取锁,Mark Word 记录该线程 ID。
 - 之后该线程再次获取锁时无需 CAS 或 Monitor 竞争,直接进入临界区。
 - 偏向锁是为 减少同一线程重复加锁的开销 而设计。
 
2️⃣ 轻量级锁 (Lightweight Lock)
- 当偏向锁遇到另一个线程竞争,撤销偏向,进入轻量级锁。
 - 每个线程在栈中创建 Lock Record,把 Mark Word 的值复制到 Lock Record 中。
 - 使用 CAS 尝试用栈锁替换对象的 Mark Word。
 
3️⃣ 重量级锁 (Monitor/Heavyweight Lock)
- 当轻量级锁竞争失败时,膨胀为重量级锁。
 - 此时 JVM 创建一个 Monitor 对象(C++层结构体),包含 OS 级别的互斥锁(例如 pthread_mutex)。
 - 阻塞或挂起竞争失败的线程。
 
🚩 HotSpot JVM 源码层面实现
在 HotSpot 源码中,Monitor 的实现涉及 C++ 数据结构和代码路径。主要文件:
| 文件 | 主要内容 | 
|---|---|
objectMonitor.hpp/cpp | 
Monitor 对象的数据结构及方法 | 
synchronizer.cpp | 
锁获取、释放逻辑、偏向锁撤销等 | 
atomic.hpp | 
封装底层硬件的原子操作 | 
thread.cpp | 
线程状态变更、挂起、唤醒等 | 
核心数据结构:ObjectMonitor
class ObjectMonitor {
public:
    void* owner;           // 当前持有锁的线程
    int   _recursions;     // 重入次数
    ObjectWaiter *EntryList; // 等待竞争锁的线程队列
    ObjectWaiter *WaitSet;   // wait() 等待队列
    volatile int _count;     // 计数或状态标志
    ...
};
🌟 Monitor 的行为
- 当 JVM 需要 Monitor 时,它会从全局 Monitor 缓存中获取或新建。
 monitorenter会调用ObjectSynchronizer::enter()。monitorexit调用ObjectSynchronizer::exit()。- 如果 Monitor 无法立即获取,则线程被加入 
EntryList,通过 OS 原语挂起。 
部分源码(简化示例)
void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, TRAPS) {
    markOop mark = obj->mark();
    if (mark->has_bias_pattern()) {
        // 处理偏向锁逻辑
    } else if (try_lightweight_lock()) {
        // 轻量级锁成功
    } else {
        // 膨胀到重量级锁
        ObjectMonitor* mon = inflate(obj());
        mon->enter(THREAD);
    }
}
这里涉及 CAS(Compare And Swap)、内存屏障、锁膨胀、线程挂起等底层操作。
🚩 硬件层面支持
synchronized 最终需要硬件支持:
- CAS 原子指令(如 x86 上的 
LOCK CMPXCHG) - 内存屏障(Memory Barrier) 确保指令顺序和可见性
 - 操作系统互斥量(重量级锁时)
 
🚩 性能优化:锁的升级/降级
HotSpot 在锁实现中提供:
- 偏向锁升级为轻量级锁(多线程竞争时)
 - 轻量级锁升级为重量级锁(自旋失败时)
 - 在无竞争时,锁可以从重量级降级回轻量或偏向锁(特定 JVM 配置下)
 
🚩  synchronized 的设计在 JVM 内部是非常精妙的:
✅ 它利用对象头的 Mark Word,实现锁状态切换几乎无额外内存开销。
✅ HotSpot 的锁优化(如偏向锁、轻量级锁、自旋、自适应自旋)结合了硬件原子指令、内存屏障和操作系统支持,实现了高效并发。
但:
⚠ 当竞争激烈时(锁膨胀为重量级锁),性能可能大幅下降,因此在高并发场景 synchronized 的替代方案(如 java.util.concurrent 中的 Lock)也应考虑。
如果想要进一步了解 HotSpot实现 的具体源码路径和调用栈中的关键帧,可以继续向下阅读
🌟 synchronized 对应的 JVM 调用栈总览
当 Java 字节码中的 monitorenter / monitorexit 被执行时,JVM 的执行路径主要涉及以下几个层次:
字节码执行器(Interpreter / C1 / C2 JIT)  
 ⬇
字节码解释 / 编译后机器码调用 JVM runtime  
 ⬇
ObjectSynchronizer / ObjectMonitor(C++ 实现锁机制)  
 ⬇
atomic 操作、内存屏障、OS 原语(重量级锁时)
🚀 主要函数调用链(简化版本)
假设一个线程执行 monitorenter:
1️⃣ 字节码执行:
- 
字节码解释器或 JIT 生成的机器码调用:
InterpreterRuntime::monitorenter(...)或编译器内联生成锁代码直接调用 runtime。
 
2️⃣ 进入同步器逻辑:
ObjectSynchronizer::enter(Handle obj, BasicLock* lock, TRAPS)
- 核心:尝试锁的不同形态(偏向、轻量、重量)
 
3️⃣ 尝试偏向锁:
// 在 mark word 检查偏向模式并尝试获取
if (mark->has_bias_pattern()) {
   BiasedLocking::revoke_and_rebias(...)
}
4️⃣ 尝试轻量级锁(CAS + Lock Record):
// 轻量级锁逻辑
if (cas_mark_word_success) {
   // 获得轻量级锁
} else {
   inflate_and_enter(...)
}
5️⃣ 锁膨胀为重量级:
ObjectMonitor* monitor = ObjectSynchronizer::inflate(...)
monitor->enter(...)
6️⃣ Monitor 实际执行:
ObjectMonitor::enter(Thread *thread)
- 
尝试自旋、队列挂起(EntryList)
 - 
当无法获取锁时,线程加入 Monitor 的 EntryList 并挂起:
os::PlatformEvent::park() // OS 级挂起线程 
7️⃣ 解锁过程:
ObjectSynchronizer::exit(...)
ObjectMonitor::exit(...)
- 释放锁,唤醒等待线程。
 
🗂 HotSpot 源码路径
这里给出源码主要文件和关键函数所在位置(基于 OpenJDK HotSpot 源码布局):
| 文件 | 路径 | 主要职责 | 
|---|---|---|
objectMonitor.hpp/cpp | 
hotspot/share/runtime/ | 
Monitor 数据结构、enter/exit 等操作 | 
synchronizer.cpp | 
hotspot/share/runtime/ | 
ObjectSynchronizer 的入口逻辑、锁膨胀、撤销偏向等 | 
biasedLocking.cpp | 
hotspot/share/runtime/ | 
偏向锁的撤销与重偏向处理 | 
interpreterRuntime.cpp | 
hotspot/share/interpreter/ | 
字节码层 monitorenter/monitorexit 调用 runtime | 
atomic.hpp | 
hotspot/share/runtime/ | 
封装底层 CAS 操作等 | 
os_linux.cpp (或其他 OS 文件) | 
hotspot/os/linux/ | 
OS 层线程挂起唤醒实现 (如 futex/pthread) | 
🌱 函数调用栈实例(基于 monitorenter)
如果您在调试或阅读源码时跟踪,可以看到类似调用链:
InterpreterRuntime::monitorenter
  ⬇
ObjectSynchronizer::enter
  ⬇
ObjectSynchronizer::inflate(必要时)
  ⬇
ObjectMonitor::enter
  ⬇
os::PlatformEvent::park(线程挂起时)
如果是 JIT 编译器路径:
C1/C2 编译器生成机器码
  ⬇
直接内联 CAS 检查逻辑
  ⬇
失败时调用 ObjectSynchronizer::enter
解锁时:
InterpreterRuntime::monitorexit
  ⬇
ObjectSynchronizer::exit
  ⬇
ObjectMonitor::exit
  ⬇
os::PlatformEvent::unpark(唤醒线程)
📝 关键数据结构与字段(objectMonitor.hpp)
class ObjectMonitor {
 public:
   void*       _owner;         // 当前持有锁的线程
   intptr_t    _recursions;    // 重入次数
   ObjectWaiter* EntryList;    // 竞争锁线程队列(EntryList)
   ObjectWaiter* WaitSet;      // wait() 等待线程队列(WaitSet)
   volatile int _count;        // 锁状态(例如膨胀标志)
   ...
};
在 ObjectSynchronizer::enter 中:
- 判断锁类型(偏向、轻量、重量)
 - 必要时调用 
inflate创建/获取 Monitor 实例 - 最终调用 
monitor->enter(thread),执行自旋、自适应自旋、或加入 EntryList 队列 
💡 ChatGPT 的观点
从我的角度看,HotSpot 对 synchronized 的实现是一种高性能权衡设计:
✅ 不同锁模式的层级退化/升级机制(偏向 -> 轻量 -> 重量)非常适合大多数 Java 应用的锁竞争分布特征。
✅ 调用链层次清晰,HotSpot 团队把复杂性封装在 ObjectSynchronizer 和 ObjectMonitor 中,保持解释器和 JIT 的一致性。
✅ 跨平台兼容性好,底层调用 os::PlatformEvent 等接口,支持不同操作系统(Linux 下 futex / pthread_mutex,Windows 下 semaphore)。
⚠ 但需要注意的是:
重量级锁一旦触发,会带来显著上下文切换开销。因此在高并发设计中,尽量减少重量级锁的可能(例如通过锁粗化、锁消除、java.util.concurrent 替代等手段)。
📌 总结
🔹 热点路径核心函数:
InterpreterRuntime::monitorenter ➡ ObjectSynchronizer::enter ➡ ObjectMonitor::enter
InterpreterRuntime::monitorexit ➡ ObjectSynchronizer::exit ➡ ObjectMonitor::exit
🔹 热点源码文件:
hotspot/share/runtime/objectMonitor.cpp
hotspot/share/runtime/synchronizer.cpp
hotspot/share/interpreter/interpreterRuntime.cpp
hotspot/share/runtime/atomic.hpp
完
                    
                
                
            
        
浙公网安备 33010602011771号