可重入锁指同一线程可多次获取同一把锁而不被自身阻塞,其通过线程专属的持有计数器实现:首次获取时计数置1并标记线程id,重复获取则计数加1,每次释放减1,仅当计数归零才真正释放锁供其他线程竞争。

synchronized 本身不是“避免死锁”的机制,而是天然支持可重入锁,这能减少某些因重复加锁导致的死锁风险,但不能从根本上防止死锁。它的可重入性是 JVM 层面的内置保障,无需手动实现。
什么是可重入锁?
可重入锁指同一个线程可以多次获取同一把锁,而不会被自己阻塞。例如:一个 synchronized 方法调用另一个本类的 synchronized 方法,线程能直接进入,不会卡住。
这是因为 JVM 为每个 monitor(锁对象)维护了一个计数器和持有线程 ID:
- 首次获取锁时,计数器置为 1,记录当前线程 ID;
- 同一线程再次进入,计数器 +1;
- 每次退出 synchronized 块/方法,计数器 -1;
- 只有计数器归零时,锁才真正释放,其他线程才可能竞争。
synchronized 的可重入性如何防止“自锁死”?
没有可重入性时,下面代码会死锁(但实际不会):
public synchronized void methodA() {
methodB(); // 调用本类另一个 synchronized 方法
}
public synchronized void methodB() {
// do something
}
如果锁不可重入,线程进入 methodA 后已持锁,再调 methodB 就要再次申请同一把锁 → 阻塞 → 永远等不到自己释放 → 死锁。synchronized 天然可重入,所以这段代码安全执行。
但它不能防止真正的多线程死锁
可重入只解决“自己锁自己”的问题,对以下典型死锁无能为力:
- 线程 A 持有锁 L1,尝试获取 L2;
- 线程 B 持有锁 L2,尝试获取 L1;
- 双方僵持,形成循环等待。
这种死锁与可重入性无关,synchronized 不会检测或打破这种依赖环。预防需靠设计:按固定顺序加锁、使用 tryLock 设置超时、减少锁粒度、避免嵌套锁等。
对比 ReentrantLock 的可重入性
synchronized 和 ReentrantLock 都是可重入锁,但实现方式不同:
- synchronized 是 JVM 内置,基于 monitor 对象的 owner 和 entry count;
- ReentrantLock 是 Java 类,内部用 AQS(AbstractQueuedSynchronizer)维护 state 和 exclusiveOwnerThread;
- 两者都支持可重入,但 ReentrantLock 提供更多控制(如公平性、中断响应、条件队列)。
注意:synchronized 不可手动释放或查询持有状态,也不支持条件变量(wait/notify 除外),这是它和 ReentrantLock 的关键区别。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











