synchronized 的可重入性:避免死锁的隐藏武器

时间:2025-09-09 14:30:02来源:互联网

下面小编就为大家分享一篇synchronized 的可重入性:避免死锁的隐藏武器,具有很好的参考价值,希望对大家有所帮助。

摘要

synchronized 关键字具备 可重入性(Reentrancy),同一线程在持有锁的情况下,可以再次获取同一把锁而不会阻塞。本文将从概念、代码示例、JVM 实现机制和工程实践四个方面,深入解析 synchronized 的可重入性。


正文

一、什么是可重入性?

可重入性(Reentrant)是指 同一线程在持有锁时,可以重复进入被同一个锁保护的临界区,而不会发生死锁。

换句话说:如果锁是“可重入”的,那么一个线程在进入某个 synchronized 方法/代码块后,还能继续调用另一个需要同一把锁的 synchronized 方法。


二、代码示例

1. 方法递归调用
public class ReentrantDemo {
    public synchronized void methodA() {
        System.out.println(Thread.currentThread().getName() + " 进入 methodA");
        methodB(); // 再次请求同一个锁
    }

    public synchronized void methodB() {
        System.out.println(Thread.currentThread().getName() + " 进入 methodB");
    }

    public static void main(String[] args) {
        ReentrantDemo demo = new ReentrantDemo();
        new Thread(demo::methodA, "T1").start();
    }
}

结果:线程 T1 先进入 methodA,随后 不会阻塞,而是直接进入 methodB,因为这是同一线程在请求同一把对象锁。

2. 父子类继承中的可重入性
class Parent {
    public synchronized void doSomething() {
        System.out.println("父类方法执行");
    }
}

class Child extends Parent {
    @Override
    public synchronized void doSomething() {
        System.out.println("子类方法执行");
        super.doSomething(); // 依然是同一把锁
    }
}

结果:子类方法调用父类方法不会造成死锁,因为锁是可重入的。


三、JVM 如何实现可重入性?

在 JVM 中,synchronized 是基于 对象头中的 Monitor(监视器锁) 实现的。
Monitor 内部维护了一个 计数器(recursions) ,用于记录线程重入的次数。

  • 第一次获取锁:计数器从 0 → 1,线程成为锁的拥有者。
  • 同一线程再次获取锁:计数器 +1。
  • 退出同步块/方法:计数器 -1。
  • 计数器归零:锁才真正释放,其他线程才能获取。

这就是为什么 synchronized 能避免 同一线程自我阻塞 的根本原因。


四、可重入性的优势

  1. 避免死锁
  • 如果没有可重入性,线程在调用 methodA() 的时候进入 methodB() 就会死锁。
  1. 提升编程灵活性
  • 允许在继承、递归调用中安全地使用 synchronized
  1. 降低锁使用的复杂度
  • 开发者无需手动判断当前线程是否持有锁,简化了并发编程模型。

五、工程实践建议

  1. 理解可重入,但不要滥用
  • 可重入不是性能优化手段,而是一种安全保证。
  • 不要因为“可重入”就随意嵌套锁,仍需控制临界区大小。
  1. 注意递归调用的深度
  • 虽然可重入避免了死锁,但无限递归依然可能导致栈溢出。
  1. 对比 ReentrantLock
  • ReentrantLock 也支持可重入,并提供了更多功能(可中断、公平锁、条件队列)。
  • 在需要灵活控制时,可以考虑替代 synchronized

六、总结

synchronized 的可重入性是并发编程中的重要特性:

  • 同一线程可以重复进入锁保护的代码,不会造成自我死锁;
  • 底层通过 Monitor 的计数器 实现;
  • 在递归、继承等复杂场景下尤为重要。

理解可重入性,可以帮助我们在设计并发程序时写出更加 安全、简洁、易维护 的代码。

本站部分内容转载自互联网,如果有网站内容侵犯了您的权益,可直接联系我们删除,感谢支持!