synchronized 可重入的核心在于 JVM Monitor 维护“持有线程 + 重入计数器”:首次加锁设 _Owner 为当前线程、_RecursionCount 为 1;重入时仅递增计数;仅当计数减至 0 才清空 _Owner 并释放锁。

synchronized 能实现可重入锁的嵌套调用,核心在于 JVM 对每个对象监视器(monitor)内部维护了一个“持有线程 + 计数器”的机制。同一线程重复进入同一把锁时,不会阻塞,而是递增计数;每次退出同步块或方法时,计数减一;只有计数归零,锁才真正释放。
锁计数器是关键
每个被 synchronized 锁定的对象,其 monitor 中包含两个关键信息:
- 当前持有锁的线程 ID(只记录一个线程)
- 该线程获取这把锁的次数(重入计数器)
当线程第一次执行 monitorenter 指令时,计数器设为 1;再次进入同一把锁(比如调用另一个 synchronized 方法),计数器加 1;每次 monitorexit 执行,计数器减 1。只要计数器 > 0,该线程就始终持有锁,其他线程无法抢占。
嵌套调用的典型场景
以下三类嵌套都依赖该机制正常运行:
- 同步方法内调用另一个同步方法:如 methodA() 是 synchronized,内部调用同样被 synchronized 修饰的 methodB(),无需重新竞争锁
- 同步代码块中再嵌套同步代码块:同一个锁对象(如 this 或 new Object())被多次用于 synchronized(...),计数器累加
- 递归调用自身:synchronized 方法里直接调用自己,每进一层计数 +1,直到栈溢出或条件退出
继承与重写中的可重入表现
子类重写父类的 synchronized 方法,并在重写方法中调用 super.method(),也属于可重入调用:
- 因为锁对象仍是 this(实例锁),整个调用链都在同一线程、同一把锁上
- JVM 不区分“谁声明了 synchronized”,只看“当前线程是否已持有该对象的锁”
- super.method() 的同步入口不会触发阻塞,而是直接通过,计数器 +1
和不可重入行为的对比
如果 synchronized 不可重入,下面代码会死锁:
synchronized(this) {System.out.println("第一层");
synchronized(this) {
System.out.println("第二层"); // 永远执行不到
}
}
但实际能输出两行——这正是可重入机制在起作用:第二层 synchronized 不申请新锁,只是增加计数。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











