Java多线程 定位死锁--jstack
文章目录
- 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
可以看到如下的四个线程发生了死锁.
还没有评论,来说两句吧...