多线程死锁

1.什么是死锁?

死锁: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

2.死锁产生的原因

1.因为系统资源不足。
2.进程运行推进的顺序不合适。
3.资源分配不当。

产生死锁的条件有四个:
1.互斥条件:所谓互斥就是进程在某一时间内独占资源。
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

3.图解死锁产生的过程

在这里插入图片描述
1)有两个人——线程A、线程B。有两个房间——房间A、房间B。每个房间上有且仅有一把锁,此处可以把锁理解为进入房间的令牌
2)线程A拿到了a锁并且成功进入了A房间
3)线程B拿到了b锁并且成功进入了B房间
4)线程A拿着a锁想要进入B房间,与此同时线程B拿着b锁想要进入A房间
那么问题来了,线程A想进B房间需要拿到b锁,而b锁在线程B手中.同样,线程B想进A房间需要拿到a锁,而a锁在线程A手中
这样如果在外界没有干预的情况下 A会一直试图进入B房间却拿不到b锁,B也会一直试图进入A房间拿不到a锁 就这样一直耗下去 于是就产生了死锁现象

4.代码模拟上图中死锁现象

package com.lzh;

public class DeadLock implements Runnable{
    private Object lockA = new Object();//A锁
    private Object lockB = new Object();//B锁

    private static Boolean flag = true;
    public void run() {
        if (flag){
            comeRoom1();//A2.最开始flag是true A进入A房间
        }else {
            comeRoom2();//B4.线程B进入B房间
        }
    }

    public void comeRoom1() {
        synchronized (lockA){
            System.out.println("线程"+Thread.currentThread().getName()+"进入了房间1");
            try {
                Thread.sleep(200);//A3.让线程A在A房间等待0.2s(给线程B进入B房间的时间 产生同一时刻A在A房间、B在B房间的情景)
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            comeRoom2();//A4.让线程A在持有A锁的情况下进入房间B
        }
    }

    public void comeRoom2() {
        synchronized (lockB){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程"+Thread.currentThread().getName()+"进入了房间2");
            comeRoom1();//B5.让线程B在持有B锁的情况下进入房间A
        }
    }

    public static void main(String[] args) {
        DeadLock deadLock2 = new DeadLock();
        Thread t1 = new Thread(deadLock2,"A");//线程A
        Thread t2 = new Thread(deadLock2,"B");//线程B
        t1.start();//A1.开始执行线程A 让A进入A房间
        try {
            Thread.sleep(200);//B1.先让主线程等待0.2s 确保A先进入了A房间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = false;//B2.flag改成false 帮助B进入B房间
        t2.start();//B3.线程B开启
    }
}

代码中注释仅供帮助理解 并不代表真实的线程执行顺序
运行结果如下:产生死锁
在这里插入图片描述

5.死锁检测

5.1 使用jconsole

首先进入你的jdk安装路径的bin目录下 我这里是C:\Program Files\Java\jdk1.8.0_171\bin
找到jconsole.exe并打开 我在本地环境下运行的类是下图红框中的com.lzh.DeadLock 点击连接
在这里插入图片描述
点击线程 再找到对应的线程 可以看到"已锁定"三个字 并且也标明了死锁产生的位置在(DeadLock.java:31 DeadLock.java:24)
在这里插入图片描述

5.2 使用jvisualvm

首先进入你的jdk安装路径的bin目录下 我这里是C:\Program Files\Java\jdk1.8.0_171\bin
找到jvisualvm.exe并打开
操作如下图
在这里插入图片描述

6.总结

发生死锁的原因主要由于:
线程之间交错执行
解决:以固定的顺序加锁
执行某方法时就需要持有锁,且不释放
解决:缩减同步代码块范围,最好仅操作共享变量时才加锁
永久等待
解决:使用tryLock()定时锁,超过时限则返回错误信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值