###重入锁死
重入锁死是一种类似于死锁和嵌套管程失败的情景。
如果一个线程重入获得了一个非重入的锁,读写锁或者一些其他的同步器就会发生重入锁死。重入意味着一个线程已经持有了一个锁可以再次持有它。Java的同步块是可以冲入的。因此,下面这段代码执行将不会出现问题。
public class Reentrant{
public synchronized outer(){
inner();
}
public synchronized inner(){
//do something
}
}
outer
和inner
方法都被声明为synchronized,这等同于一个synchronized(this)
块。如果一个线程在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()
将会阻塞。一个重入锁死就发生了。
要避免重入锁死你有两种选择:
- 编写代码避免获取已经持有的锁
- 使用可重入锁
使用哪种方法更适合于你的程序取决于具体的情景。可重入锁的性能常常不如非重入锁,而且更难实现,可重入锁通常没有不可重入锁那么好的表现,而且实现起来复杂,但这些情况在你的项目中也许算不上什么问题。无论你的项目用锁来实现方便还是不用锁方便,可重入特性都需要根据具体问题具体分析。