什么是可重入,什么是可重入锁? 它用来解决什么问题?
在 Java 并发编程中,“可重入” 是一个非常重要的概念。它关系到线程如何获取锁,是否允许一个线程多次进入同一个锁保护的代码块。
一、什么是可重入(Reentrancy)?
可重入(Reentrancy),又称“递归锁”,是指:
同一个线程在外层方法获得锁之后,在进入内层方法时,如果尝试获取同一个锁,仍然能够获取成功。
简单理解:
- 自己可以再次进入自己已经拥有的锁,而不会造成死锁。
二、什么是可重入锁(Reentrant Lock)?
可重入锁是一种允许同一个线程多次获得同一把锁而不会被阻塞的锁。Java 中最常见的可重入锁有两个:
| 可重入锁 | 所在包 | 特点 |
|---|---|---|
synchronized | Java 语言内置关键字 | 可重入,自动管理重入计数 |
ReentrantLock | java.util.concurrent.locks | 可重入,支持可中断、公平锁、尝试锁等特性 |
三、举个例子:可重入锁的代码演示
示例:synchronized 的可重入性
public class ReentrantExample {
public synchronized void outer() {
System.out.println("外层方法");
inner(); // 当前线程再次进入 synchronized 方法
}
public synchronized void inner() {
System.out.println("内层方法");
}
public static void main(String[] args) {
new ReentrantExample().outer();
}
}
输出:
外层方法
内层方法
即:一个线程已经持有了某对象的锁,还可以再次进入该对象的 synchronized 方法。
四、ReentrantLock 的重入特性
ReentrantLock lock = new ReentrantLock();
public void outer() {
lock.lock();
try {
System.out.println("outer");
inner();
} finally {
lock.unlock();
}
}
public void inner() {
lock.lock();
try {
System.out.println("inner");
} finally {
lock.unlock();
}
}
输出:
outer
inner
同一个线程多次调用 lock(),不会死锁,但需要手动调用多次 unlock()。
五、可重入锁解决了什么问题?
如果没有可重入特性,代码中会容易出现死锁问题:
// 假设锁不可重入,以下代码将死锁
synchronized(obj) {
// 已经获得 obj 的锁
synchronized(obj) {
// 再次请求 obj 的锁,但锁不可重入 → 死锁!
}
}
可重入锁解决的问题:
| 问题类型 | 说明 |
|---|---|
| 避免死锁 | 同一个线程可以重复进入临界区 |
| 实现递归调用同步 | 方法 A 中调用方法 B,二者都加锁同一个对象 |
| 简化程序设计 | 无需人为跟踪是否已持有锁 |
六、可重入锁底层实现机制
synchronized:
- JVM 维护一个锁计数器(reentrant count)
- 第一次进入:计数器为 1
- 再次进入同一锁:计数器 +1
- 每次
exit monitor:计数器 -1,直到为 0 才真正释放锁
ReentrantLock:
- 使用一个 state 变量记录加锁次数
- 同一个线程重复调用
lock(),state 累加 - 每次
unlock(),state 减一,直到为 0 才释放锁
七、相关资料推荐
- 📘 《Java 并发编程实战》:第 13 章 可重入锁
- 📘 《深入理解 Java 虚拟机》:锁优化与原理
- 🔗 JDK ReentrantLock 源码
- 🔗 JLS – Java Language Specification on synchronized
总结口诀
一锁在手,再进无忧;多次加锁,不死不休。
可重入锁解递归之困,防死锁于未然。
更多详细内容请关注其他相关文章!