死锁详解

死锁

互相等待对方释放锁

死锁的条件
  • 互斥条件
    资源是独占的且排他使用,进程互斥使用资源,即任意时刻一个资源只能给一个进程使用。
  • 不可剥夺条件
    进程所获得的资源在未使用完毕之前,不被其他进程强行剥夺,而只能由获得该资源的进程资源释放
  • 请求和保持条件
    进程每次申请它所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源
  • 循环等待条件
    若干进程间形成首尾相接循环等待资源的关系
死锁处理方法
预防死锁
  1. 破坏“占有并等待”条件:就是在系统中不允许进程在已获得某种资源的情况下,申请其他资源。即要想出一个办法,阻止进程在持有资源的同时申请其他资源
    ​ 方法一:创建进程时,要求它申请所需的全部资源,系统或满足其所有要求,或什么也不给它。这是所谓的 “ 一次性分配”方案
    ​ 方法二:要求每个进程提出新的资源申请前,释放它所占有的资源。这样,一个进程在需要资源S时,须先把它先前占有的资源R释放掉,然后才能提出对S的申请,即使它可能很快又要用到资源R
  2. 破坏“不可抢占”条件:允许对资源实行抢夺
    ​ 方法一:如果占有某些资源的一个进程进行进一步资源请求被拒绝,则该进程必须释放它最初占有的资源,如果有必要,可再次请求这些资源和另外的资源
    ​ 方法二:如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。只有在任意两个进程的优先级都不相同的条件下,方法二才能预防死锁
  3. 破坏“循环等待”条件:将系统中的所有资源统一编号,进程可在任何时刻提出资源申请,但所有申请必须按照资源的编号顺序(升序)提出。这样做就能保证系统不出现死锁
避免死锁
  • 所有获取资源的线程按照一定的顺序获取资源
  • 银行家算法,是指在分配资源之前先进行安全性检查,资源分配后是否会导致系统死锁。如果会死锁,则不分配,否则就分配
解除死锁

一旦检测出死锁,就应立即釆取相应的措施,以解除死锁

  • 资源剥夺法:挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程
  • 撤销进程法:强制撤销部分、甚至全部死锁进程并剥夺这些进程的资源。撤销的原则可以按进程优先级和撤销进程代价的高低进行。
  • 进程回退法:让一(多)个进程回退到足以回避死锁的地步,进程回退时自愿释放资源而不是被剥夺。要求系统保持进程的历史信息,设置还原点
手写死锁-java
class Server implements  Runnable {
     public String userName;
     public Object object1=new Object();
     public Object object2=new Object();
     public void setUserName(String userName){
            this.userName=userName;
     }
    public void run(){
         if(userName.equals("a")){
             synchronized (object1){  //a已获取锁
                 System.out.println("userame: "+userName);
                 try {
                     Thread.sleep(2000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 //synchronized 是可重入锁
                 synchronized (object2){   //等待b释放锁
                     System.out.println("first--object1  end--object2");
                 }
             }


         }
         if(userName.equals("b")){
             synchronized (object2) {  //b已获取锁
                 System.out.println("userame: " + userName);
                 try {
                     Thread.sleep(2000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 synchronized (object1) {   //等待a释放锁
                     System.out.println("first--object2 end--object1");
                 }
             }
         }
    }
}

public class DealThread {
    public static void main(String[] args) {
        try {
              Server server1=new Server();
              server1.setUserName("a");
              Thread thread=new Thread(server1);
              thread.start();
              Thread.sleep(1000);

              server1.setUserName("b");
              Thread thread1=new Thread(server1);
              thread1.start();
        } catch (InterruptedException e) {
              e.printStackTrace();
        }
    }
}
Java死锁查看分析方法
Jconsole

jconsole是jdk自带的工具,用它来监控Java的运行情况

  • 打开cmd然后输入jconsole打开
    在这里插入图片描述
  • 连接到需要查看的进程
    在这里插入图片描述
  • 打开线程选项卡,然后点击左下角的“检测死锁”, jconsole就会给我们检测出该线程中造成死锁的线程,点击选中即可查看详情
    在这里插入图片描述
    从上图中可看出:
    在线程Thread-1中,从状态可以看出,它想申请java.lang.Object@6b9476fe这个资源,但是这个资源已经被Thread-0拥有了,所以就堵塞了
    Thread-1一直等待java.lang.Object@6b9476fe资源,而Thread–0一直也等待java.lang.Object@474a97ed资源,于是这两个线程就这么僵持了下去,造成了死锁
Jstack

Jstack是JDK自带的命令行工具,主要用于线程Dump分析

  • 先用Jps来查看java进程id(或者Linux的ps命令)
    在这里插入图片描述
  • jstack输出线程dump信息到文件
    在这里插入图片描述
  • 查看log文件,然后进行分析
    在这里插入图片描述
    其中有一行是at Server.run(DeadThread.java:20),说明Thread-0是在DeadThread类的20行处发生死锁…剩余内容省略
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值