- 原文地址:Reentrance Lockout
- 作者: Jakob Jenkov
如果线程重入进锁/读写锁或者其他不可重入的同步机制,那么就可能发生重入锁死。 重入意味着一个线程可以重复获得已经持有的锁。 Java中的
synchronized
同步块就是可重入的。 因此,下面这个代码是可以正常工作的:
public class Reentrant{
public synchronized outer(){
inner();
}
public synchronized inner(){
//do something
}
}
注意:
outer()
和inner()
都声明为synchronized
,这在Java中等价于synchronized(this)
。 由于两个方法实际都是由对象this
上的监控器来保持同步的,所以,当某个线程调用outer()
时,不会影响内部再次调用inner()
的。 这就是说,当某个线程已经持有某个对象上的监控器时,此线程就可以访问此监控器下的所有同步代码块。 这就是所谓的重入。 我们先来看看一个不可重入的Lock
实现:
public class Lock{
private boolean isLocked = false;
public synchronized void lock()
throws InterruptedException{
while(isLocked){
wait();
}
isLocked = true;
}
public synchronized void unlock(){
isLocked = false;
notify();
}
}
如果某个线程调用了
lock()
两次,而期间没有调用过unlock()
,这就会导致第二次lock()
调用会阻塞。这就会引发重入锁死问题。
要想避免重入锁死,可以采用以下两种方式:
- 业务逻辑采用不许要重新加锁的实现方案
- 使用可重入锁实现
实际使用时,需要结合具体情况,来采用不同的处理方案。 并不是说,可重入锁就一定比不可重入锁要好。 另外,不论选择何种方案,最终都需要充分设计,以及充分的测试。