我们来模拟一个 死锁 的案例,假设有这样一个检测黑盒子, 黑盒 有2扇门A、B,
检测物体时,既可以从A进入,也可以从B进入,规则如下:
若物体从A进入后,A门会关上,待检测完毕,物体必须从B出盒,然后A门才会重新打开
同样,
若物体从B进入后,B门会关上,待检测完毕,物体必须从A出盒,然后B门才会重新打开
如果我们让2个物体分别从A、B门进入检测,可想而知,2个物体都出不了盒子
现实模型的黑盒如下
//定义A门
class DoorA{
public void enter(){
System.out.println("从A门进入黑盒") ;
}
public void check(){
try{
System.out.println("A进入后,黑盒检查中。。。。。。") ;
Thread .sleep(5000) ;
}catch(InterruptedException e){
e.printStackTrace() ;
}
System.out.println("A门检查完毕,等待B门打开") ;
}
public void outer(){
System.out.println("从B门出黑盒成功,A门打开") ;
}
}
//定义B门
class DoorB{
public void enter(){
System.out.println("从B门进入黑盒") ;
}
public void check(){
try{
System.out.println("B进入后,黑盒检查中。。。。。。") ;
Thread.sleep(5000) ;
}catch(InterruptedException e){
e.printStackTrace() ;
}
System.out.println("B门检查完毕,等待A门打开") ;
}
public void outer(){
System.out.println("从A门出黑盒成功,B门打开") ;
}
}
/**
* 死锁demo
* @author ssj
*
*/public class DeadLock implements Runnable{
private static DoorA doorA = new DoorA() ; // 实例化static型对象
private static DoorB doorB = new DoorB() ; // 实例化static型对象
private String direct ; // 进入方向
public void run(){ // 覆写run()方法
if("A".equals(direct)){
synchronized (doorA){ // 进入方向
doorA.enter();
doorA.check();//检查需要一定的时间,此方法有睡眠延迟
//获取B门的锁
synchronized(doorB){
doorA.outer(); ;
}
}
}else if("B".equals(direct)){
synchronized(doorB){
doorB.enter();
doorB.check();//检查需要一定的时间,此方法有睡眠延迟
//获取A门的锁
synchronized(doorA){
doorB.outer(); ;
}
}
}
}
public static void main(String args[]){
DeadLock t1 = new DeadLock() ;
DeadLock t2 = new DeadLock() ;
t1.direct = "A" ;// 进入方向
t2.direct = "B" ;// 进入方向
Thread thA = new Thread(t1) ;
Thread thB = new Thread(t2) ;
thA.start() ;
thB.start() ;
}
}
运行上面的代码结果:
为啥两个物体都获取不到对面的门的锁呢?
分析:
1 一开始,A、B门都没有锁,两个物体a、b可以分别从A、B进入盒子中
2 两个物体a、b都进入后,A、B门分别关上
3 两个物体在盒子中检测,检测是需要等待一定的时间的
4 检测完毕,开始出盒。
若a先检测完毕,物体a想从B门出,可是B门此时关着,B门只有物体b从A门出去后,B门才会打开,
可是物体b要出去,也要从A门出去,但是A门此时也是关着,A门只有物体a从B门出去后才会打开,
A门和B都依赖于a和b的出盒,而a和b又依赖于B门和A的打开,这样a和b永远出不去了,形成僵持,这就是死锁了
怎样修改代码才可以避免死锁呢?
其实也是简单的,只要移动一下获取A、B锁的位置就可以了
代码修改如下,看注释部分:
public class DeadLock implements Runnable{
private static DoorA doorA = new DoorA() ; // 实例化static型对象
private static DoorB doorB = new DoorB() ; // 实例化static型对象
private String direct ; // 进入方向
public void run(){ // 覆写run()方法
if("A".equals(direct)){
synchronized(doorA){ // 进入方向
doorA.enter();
doorA.check();//检查需要一定的时间,此方法有睡眠延迟
//获取B门的锁
// synchronized(doorB){
// doorA.outer(); ;
// }
}
synchronized(doorB){
doorA.outer(); ;
}
}else if("B".equals(direct)){
synchronized(doorB){
doorB.enter();
doorB.check();//检查需要一定的时间,此方法有睡眠延迟
//获取A门的锁
// synchronized(doorA){
// doorB.outer(); ;
// }
}
synchronized(doorA){
doorB.outer(); ;
}
}
}
public static void main(String args[]){
DeadLock t1 = new DeadLock() ;
DeadLock t2 = new DeadLock() ;
t1.direct = "A" ;// 进入方向
t2.direct = "B" ;// 进入方向
Thread thA = new Thread(t1) ;
Thread thB = new Thread(t2) ;
thA.start() ;
thB.start() ;
}
}
再次运行,死锁解决
总结:
代码设计过程中,一定要避免类似synchronized的锁的嵌套,否则很容易死锁