java中每个object实例天然关联一个内置monitor锁,synchronized基于此实现同步:锁定对象、可重入、自动释放,且monitor随对象生命周期存在,不可对null加锁。

Java 中每个 Object 实例天然关联一个内部监视器锁(monitor),synchronized 块正是基于这个机制实现线程同步的——它不是额外创建锁,而是直接申请并释放该对象内置的 monitor。
每个 Object 都自带一个 monitor
在 JVM 规范中,每个 Java 对象在堆上分配时,都会附带一个与之绑定的 monitor 结构(包含锁计数器、等待队列、持有线程等信息)。这个 monitor 是对象头(Object Header)的一部分,由 JVM 自动管理,开发者无法显式创建或销毁。
- 当你写
synchronized(obj) { ... },JVM 就会尝试获取obj关联的 monitor - 如果 monitor 未被占用,当前线程立即获得锁,进入临界区
- 如果已被其他线程持有,当前线程阻塞,进入该 monitor 的等待队列,直到锁被释放
synchronized 块本质是 monitor 的 acquire/release 操作
synchronized 块编译后会生成 monitorenter 和 monitorexit 字节码指令,对应 monitor 的加锁与解锁流程:
-
monitorenter:检查 monitor 状态;若可获取,则将锁计数器置为 1,记录持有线程;若已被同一线程持有,则计数器 +1(支持可重入) -
monitorexit:计数器减 1;减到 0 时真正释放 monitor,并唤醒等待队列中的一个线程 - JVM 保证即使发生异常,也会自动插入
monitorexit(通过异常表),确保锁不会泄漏
静态方法和 this 锁的区别在于锁定的对象不同
synchronized 的目标始终是一个对象实例,区别只在于「锁哪个对象」:
-
synchronized(this)或普通同步实例方法 → 锁的是当前实例(即this引用的对象) -
synchronized(ClassName.class)或同步静态方法 → 锁的是该类的Class对象(因为Class也是Object子类,同样有 monitor) - 任意非空对象(如
private final Object lock = new Object();)→ 锁的就是那个对象,适合细粒度控制
注意 monitor 与对象生命周期强绑定
monitor 生命周期跟随对象:对象被 GC 回收前,其 monitor 一直存在;但 monitor 不会因对象内容变化而改变,哪怕对象字段全为 null 或被修改,只要引用没变,锁仍是同一个。
- 不能对
null使用synchronized,否则抛NullPointerException - 不要用可变对象(如
String、Integer常量)作锁,因为它们可能被其他代码意外共享或替换 - 推荐使用私有 final 对象作锁,明确作用域且不可篡改
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











