重入锁死是跟死锁和嵌套的监控程序锁死相似的一个场景。重入锁死也在读写锁中提到过了。
重入锁死可能会发生在如果一个线程重入一个锁中,ReadWriteLock或者一些其他的同步器不是可重入的。可重入的意味着已经持有一个锁的线程可以再一次持有它。Java的同步块是可重入的,因此下面的代码将会没有问题的工作:
public class Reentrant{
public synchronized outer(){
inner();
}
public synchronized inner(){
//do something
}
}
注意这个outer方法和inner方法是怎么被声明为同步方法的,这个跟Java中的synchronized(this)块是一样的。如果一个线程调用outer方法,然后在outer方法的内部调用inner方法是没有问题的,因为这两个方法(或者块)是在相同的监控对象上(“this”)同步的。如果一个线程在一个监控的对象上已经持有了一个锁,它可以访问相同监控对象上的所有的同步锁。这个称之为重入。这个线程可以重入它已经持有锁的任何一个代码块。
下面的这个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方法的第二次调用将会锁住。一个可重入的锁死就会发生了。
对于重入锁死你有两个选择:
- 避免写重入锁的代码。
- 使用重入锁。
这些选择具体哪个适合依赖你的具体场景。重入锁经常不会作为一个非重入锁执行,并且他们很难去实现,但是这个在你的场景中可能不是一个问题。你的代码是否简单的实现重入锁或者非可重入锁,这个得具体情况具体分析。
翻译地址:http://tutorials.jenkov.com/java-concurrency/reentrance-lockout.html