Java中synchronized和ReentrantLock锁重入机制详解
2026/9/19 10:29:53 网站建设 项目流程

在Java中,锁的重入(Reentrancy)是指同一个线程可以多次获取同一把锁而不会造成死锁的特性。这是Java内置锁(synchronized)和ReentrantLock的一个重要特性。

核心概念

当一个线程已经持有某个锁时,它可以再次请求获取这个锁,JVM会记录锁被同一个线程持有的次数,只有当锁完全释放(计数器归零)时,其他线程才能获取该锁。

synchronized的锁重入示例

publicclassReentrantDemo{publicsynchronizedvoidmethodA(){System.out.println("进入methodA");methodB();// 调用另一个同步方法System.out.println("离开methodA");}publicsynchronizedvoidmethodB(){System.out.println("进入methodB");// 做一些操作System.out.println("离开methodB");}publicstaticvoidmain(String[]args){ReentrantDemodemo=newReentrantDemo();// 同一个线程可以重入锁newThread(()->demo.methodA()).start();}}

输出:

进入methodA 进入methodB 离开methodB 离开methodA

ReentrantLock的锁重入示例

importjava.util.concurrent.locks.ReentrantLock;publicclassReentrantLockDemo{privatefinalReentrantLocklock=newReentrantLock();publicvoidouter(){lock.lock();try{System.out.println("外层方法,锁重入计数: "+lock.getHoldCount());inner();// 调用内层方法,重入锁}finally{lock.unlock();}}publicvoidinner(){lock.lock();try{System.out.println("内层方法,锁重入计数: "+lock.getHoldCount());}finally{lock.unlock();}}publicstaticvoidmain(String[]args){ReentrantLockDemodemo=newReentrantLockDemo();demo.outer();}}

输出:

外层方法,锁重入计数: 1 内层方法,锁重入计数: 2

锁重入的实现机制

1. synchronized的实现

  • JVM为每个锁对象维护一个计数器
  • 当线程第一次获取锁时,计数器=1
  • 每次重入,计数器+1
  • 每次退出同步代码块,计数器-1
  • 计数器归零时,锁完全释放

2. ReentrantLock的实现

  • 使用AQS(AbstractQueuedSynchronizer)的state字段记录重入次数
  • 通过getHoldCount()方法可以获取当前线程的重入次数

为什么需要锁重入?

1.避免死锁

// 如果没有锁重入,这段代码会导致死锁publicclassWithoutReentrancy{publicsynchronizedvoida(){b();// 调用另一个同步方法}publicsynchronizedvoidb(){// 一些操作}}

2.支持面向对象的设计

  • 子类可以重写父类的同步方法
  • 方法可以调用其他同步方法
  • 支持递归调用

锁重入的注意事项

1.释放次数必须匹配

publicclassLockReleaseExample{privatefinalReentrantLocklock=newReentrantLock();publicvoidwrong(){lock.lock();lock.lock();// 重入// 业务逻辑lock.unlock();// 只释放一次,锁没有完全释放!}publicvoidcorrect(){lock.lock();lock.lock();// 重入try{// 业务逻辑}finally{lock.unlock();// 释放一次lock.unlock();// 再释放一次}}}

2.可重入锁 vs 不可重入锁

特性可重入锁不可重入锁
同一线程多次获取允许会导致死锁
实现复杂度较高较低
使用场景大多数情况特定场景
Java示例synchronized, ReentrantLock需要自定义实现

实际应用场景

1.递归调用

publicclassRecursiveExample{publicsynchronizedvoidrecursive(intn){if(n<=0)return;System.out.println("递归深度: "+n);recursive(n-1);// 递归调用,需要锁重入}}

2.模板方法模式

publicabstractclassTemplateMethod{publicfinalvoidtemplateMethod(){synchronized(this){doOperation1();doOperation2();// 可能需要锁保护}}protectedabstractvoiddoOperation1();protectedabstractvoiddoOperation2();}

总结

锁重入是Java并发编程中的重要特性,它:

  1. 提高了灵活性:允许方法调用其他同步方法
  2. 避免了自死锁:同一个线程不会因为重复获取锁而阻塞自己
  3. 简化了编程:开发者不需要担心嵌套同步的问题
  4. 支持面向对象设计:便于继承和多态的实现

Java中的synchronized关键字和ReentrantLock都内置了锁重入机制,这也是为什么它们被称为"可重入锁"的原因。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询