第18讲 什么情况下Java程序会产生死锁 如何定位、修复

图片右键另存为查看详细图片右键另存为查看详细。

查看详细

什么情况下Java程序会产生死锁?如何定位、修复?

死锁是一种特定的程序状态,在实体之间,由于循环依赖导致彼此一直处于等待之中,没有任何个体可以继续前进。死锁不仅仅是在线程之间会发生,存在资源独占的进程之间同样也可能出现死锁。通常来说,我们大多是聚焦在多线程场景中的死锁,指两个或多个线程之间,由于互相持有对方需要的锁,而永久处于阻塞的状态。
我们可以通过jstack或者jconsle来定位问题。

死锁产生的原因

1.竞争资源

系统中供多个进程共享的资源其数目不足以满足诸进程的需要时,会引起诸进程对资源的竞争而产生死锁。

2.进程间推进顺序非法

进程在运行过程中,请求和释放资源的顺序不当,会导致死锁。

死锁的四个必要条件

  1. 互斥条件
    一段时间内某资源只由一个进程占用。如果此时还有其它进程请求该资源,则请求者只能等待,直至占有该资源的进程用毕释放。

  2. 请求和保持条件
    进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

  3. 不剥夺条件
    指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

  4. 环路等待条件
    若干进程间形成首尾相接循环等待资源的关系。

死锁如何避免

1.尽量避免使用多个锁
2.计好锁的获取顺序
  1. 将对象(方法)和锁之间的关系,用图形化的方式表示分别抽取出来
  2. 然后根据对象之间组合、调用的关系对比和组合,考虑可能调用时序
  3. 按照可能时序合并,发现可能死锁的场景
3.使用带超时的方法,为程序带来更多可控性
  1. Object.wait(…)或者CountDownLatch.await(…)指定超时时间
  2. .ReentrantLock trylock使用时候。我们希望条件允许就尝试插队,不然就按照现有公平性规则等待。一般采用如下方法:
if (lock.tryLock() || lock.tryLock(timeout, unit)) {
// ...
}
4.静态代码分析(如FindBugs)去查找固定的模式,进而定位可能的死锁或者竞争情况

死锁检测工具

死锁demo


public class DeadLockDemo {
    private static String A = "A";
    private static String B = "B";

    public static void main(String[] args) {
        new DeadLockDemo().deadLock();
    }
    private void deadLock() {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (A) {
                    try {
                        Thread.currentThread().sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (B) {
                        System.out.println("1");
                    }
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (B) {
                    synchronized (A) {
                        System.out.println("2");
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
}

jstack

JDK自带的命令行工具,线程Dump分析。

  1. Jps来查看java进程id
  2. jstack id名

在这里插入图片描述

在这里插入图片描述

JConsole

JDK自带的图形化界面工具。

JConsole使用的就是ThreadMXBean获取死锁线程并分组,然后打印相关线程信息。

具体使用
https://blog.csdn.net/abc86319253/article/details/49534225

线程进入了死循环,导致其他线程一直等待,这种问题如何诊断?

循环死锁,会导致cpu某线程的cpu时间片占用率相当高。
Linux上,可以使用top命令配合grep Java之类,找到忙的pid;然后,转换成16进制,就是jstack输出中的格式;再定位代码。
备注:
jps -l 查看java进程

常见的死锁

java并发编程实战笔记:避免活跃性危险

发布了93 篇原创文章 · 获赞 26 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/sxj159753/article/details/96659837