Java多线程 定位死锁--jstack

jstack定位死锁

死锁发生的时候, 控制台什么也不打印, 无法进行排查. 这个时候就需要借助工具来进行定位死锁了.
工具之一就是jdk自带的命令jstack
在jdk的bin 目录中,可以看到是有jstack.exe这个应用程序的,配置好了jdk的环境变量后,那么就可以直接用jstack来分析死锁了.

两个线程死锁分析

首先分析两个线程死锁的情况
运行之前的章节中, 两个线程必然发生死锁的代码demo

package com.thread.deadlock;

/**
 * 类名称:MustDeadLock
 * 类描述:   必定发生死锁的情况
 *
 * @author: https://javaweixin6.blog.csdn.net/
 * 创建时间:2020/9/8 7:55
 * Version 1.0
 */
public class MustDeadLock implements Runnable {
    
    
    //标记位, 不同的线程根据标记位执行不同的代码
    int flag = 1 ;

    //两把锁
    static Object o1 = new Object();
    static Object o2 = new Object();

    public static void main(String[] args) {
    
    
        MustDeadLock r1 = new MustDeadLock();
        MustDeadLock r2 = new MustDeadLock();
        //给不同的线程, 设置不同的标记位
        r1.flag=1;
        r2.flag=2;

        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        t1.start();
        t2.start();
    }

    @Override
    public void run() {
    
    
        //打印出标记位
        System.out.println("flag = "+flag);
        if (flag == 1) {
    
    
            synchronized (o1) {
    
    
                try {
    
    
                    //线程1持有锁o1, 并且等待500ms ,让线程2执行
                    Thread.sleep(500);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                //线程1尝试去获取锁o2
                synchronized (o2) {
    
    
                    System.out.println("线程1成功拿到两把锁");
                }

            }
        }

        if (flag == 2) {
    
    

            synchronized (o2) {
    
    

                try {
    
    
                    //持有锁o2, 并且等待500ms ,让线程1执行
                    Thread.sleep(500);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }

                //线程2尝试去获取锁o1
                synchronized (o1) {
    
    
                    System.out.println("线程2成功拿到两把锁");
                }
            }
        }
    }
}

运行程序 , 可以看到控制台打印了1 和2之后, 再也没打印出东西了, 也没报错, 但是可以看到红色的按钮是亮着的,程序进入了阻塞的状态.

首先用jps 找出当前运行程序的PID, 可以看到我们自己运行的类MustDeadLock的PID为10052

输入jstack 10052 可以看到打印出来了线程间死锁的信息.
线程1持有0x000000076e471818这把锁, 需要0x000000076e471808这把锁.
线程0持有0x000000076e471808这把锁,需要0x000000076e471818这把锁.因此就造成了死锁.

把打印信息拖到最下面, 也可以看到 提示发现了一个死锁Found 1 deadlock

多个线程死锁分析

运行如下的多人转账的代码案例

package com.thread.deadlock;

import java.util.Random;

/**
 * 类名称:MultiTransferMoney
 * 类描述: 多人转账发生死锁demo
 *
 * @author: https://javaweixin6.blog.csdn.net/
 * 创建时间:2020/9/9 7:13
 * Version 1.0
 */
public class MultiTransferMoney {
    
    

    //账户的总数量
    private static final int NUM_ACCOUNTS = 500;

    //每个账户初始的余额
    private static final int NUM_MONEY = 1000;
    private static final int NUM_ITERATIONS = 1000000;
    private static final int NUM_THREADS = 20;

    public static void main(String[] args) {
    
    
        Random random = new Random();

        //定义转账的账户数组
        TransferMoney.Account[] accounts = new TransferMoney.Account[NUM_ACCOUNTS];

        for (int i = 0; i < accounts.length; i++) {
    
    
            //给每个账户数组中的元素定初始值
            accounts[i] = new TransferMoney.Account(NUM_MONEY);
        }

        class TransferThread extends Thread {
    
    

            @Override
            public void run() {
    
    
                //每一个线程都进行随机的转账

                for (int i = 0; i < NUM_ITERATIONS; i++) {
    
    
                    //随机获取转账方索引
                    int fromAccount = random.nextInt(NUM_ACCOUNTS);
                    //随机的获取收款方
                    int toAccount = random.nextInt(NUM_ACCOUNTS);
                    //随机获取转账金额
                    int amount = random.nextInt(NUM_MONEY);

                    //执行转账的方法
                    TransferMoney.transferMoney(accounts[fromAccount],accounts[toAccount],amount);
                }

            }
        }

        //开启20个线程进行转账
        for (int i = 0; i < NUM_THREADS; i++) {
    
    
            new TransferThread().start();
        }

    }


}

运行一段时间后, 程序进入阻塞状态了.

找出PID

执行 jstack 7464
可以看到如下的四个线程发生了死锁.

猜你喜欢

转载自blog.csdn.net/qq_33229669/article/details/108526477