您的位置 首页 java

理解java中多线程的死锁,这篇就够了

我们来模拟一个 死锁 的案例,假设有这样一个检测黑盒子, 黑盒 有2扇门A、B,

检测物体时,既可以从A进入,也可以从B进入,规则如下:

若物体从A进入后,A门会关上,待检测完毕,物体必须从B出盒,然后A门才会重新打开

同样,

若物体从B进入后,B门会关上,待检测完毕,物体必须从A出盒,然后B门才会重新打开

如果我们让2个物体分别从A、B门进入检测,可想而知,2个物体都出不了盒子

现实模型的黑盒如下

理解java中多线程的死锁,这篇就够了

黑盒模型

 //定义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的锁的嵌套,否则很容易死锁

文章来源:智云一二三科技

文章标题:理解java中多线程的死锁,这篇就够了

文章地址:https://www.zhihuclub.com/179543.shtml

关于作者: 智云科技

热门文章

网站地图