死锁

我们来看一个典型的死锁的例子

public class DeadLock implements Runnable{

    private Object o1 = new Object();
    private Object o2 = new Object();
    private int i=0;


    @Override
    public void run() {
        while(true) {
            if(i%2==0) {
                synchronized(o1) {
                    System.out.println("if o1");
                    synchronized(o2) {
                        System.out.println("if o2");
                    }
                }
            }
            else {
                synchronized(o2) {
                    System.out.println("else o2");
                    synchronized(o1) {
                        System.out.println("else o1");
                    }
                }
            }
            i++;
        }

    }
}
public class DeadTest {
    public static void main(String[] args) {
        DeadLock dl = new DeadLock();
        Thread t0 = new Thread(dl);
        Thread t1 = new Thread(dl);
        t0.start();
        t1.start();
    }
}

运行结果
在这里插入图片描述
可以看出程序进入了死循环,不再继续走下去了,这就是死锁问题!!!!

一、概念

指两个或两个以上的线程在执行过程中,由于竞争资源而造成的阻塞问题,若无外力作用下,他们将无法推进下去,此时系统处于死锁状态。
在这里插入图片描述

二、产生的原因

  • 因竞争资源产生死锁
  • 进程顺序推进不当发生死锁

三、出现死锁的必要条件

  • 互斥条件:资源每次只能是一个线程使用 ==》资源
  • 请求与保持条件:一个线程因请求资源而阻塞时,对以获取的资源保持不放 =》线程
  • 不可剥夺条件:线程已获取的资源,在未使用之前不能强行剥夺
  • 循环等待条件:若干的线程之间形成一种头尾相连接的循环等待资源关系

四、死锁的预防或解除

解决死锁的途径:预防、避免、检测和恢复

  • 预防死锁:(破坏4个必要条件)
    资源一次性分配:(破坏请求与保持条件)
    可剥夺资源:在线程未满足条件时释放掉已占有的资源
    资源有序分配:系统给每类资源赋予一个编号,每个线程按编号递增顺序请求资源,释放则相反。
  • 避免死锁(银行家算法)
    允许线程动态的申请资源,系统在资源分配之前先计算资源分配的安全性,若此次分配不会导致系统进入不安全状态,则给当前的线程分配该资源,否则进程等待。
  • 检测与解除
    当线程发现进入死锁了,立即从死锁状态解除掉,采用方式剥夺资源(从其他线程剥夺足够多的资源给死锁线程,以免除死锁状态的线程)

五、引起死锁的案例

1、生产者、消费者使用不当会产生死锁

wait、notify、notifyAll 使用不当就会产生死锁

2、多线程获取多把锁

有两把锁 lock1 和 lock2

Lock1.lock();
  lock2.lock();
  //todo
  lock2.unlock();
lock1.unlock();

注意: 先加的锁应后释放,后加的锁应先释放,否则会引起死锁

3、哲学家就餐问题

圆桌上有5位哲学家、每两位中间有一个筷子;
每个哲学家有两件事要做:思考、吃饭(哲学家必须同时拿到两个筷子才能吃饭);
哲学家之间并不知道对方何时要吃饭、何时要思考,不能协商制定吃饭、思考策略;
制定一个拿筷子的策略,使得哲学家不会因为拿筷子而出现死锁乐观锁;

六、实际定位死锁问题的思路

  • 首先需要确定java进程是否发生死锁
  • 打开 jvisualvm工具,专门分析 JVMCPU,内存使用情况,以及线程的运行信息查看当前java进程各个线程运行的状态(颜色)
  • 通过 jvisualvm 的线程 dump 或者 jstack 命令,把当前 java 进程所有线程的调用堆栈信息打印出来
  • 分析main线程和子线程有没有关键短语:
    • waiting for(资源地址)
    • waiting to lock(资源地址)
  • 看线程函数调用栈,定位到源码上,具体问题具体分析

根据开头的那个死锁代码为例:
在这里插入图片描述
部分堆栈信息:
在这里插入图片描述
还可参考该博客 死锁问题的出现和解决

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值