如果程序挂死,有时使用jstack查看进程中线程信息时,需要添加上-F参数,此时如果有死锁信息,则可能不会打印出死锁堆栈信息,使用jdb则可以查看当前死锁线程的运行堆栈。
如下模拟一个简单的死锁程序
package com.demo.bootdemo; import java.util.HashMap;
import java.util.Map; import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component; @Component
public class MyListeners implements ApplicationListener<ContextRefreshedEvent> { private Map map = new HashMap<>();
private String lock = "aa"; @Override
public void onApplicationEvent(ContextRefreshedEvent arg0) { Thread t = new Thread(new Runnable() { @Override
public void run() {
synchronized (map) {
System.out.println(Thread.currentThread().getName() + ": 获得map锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ": 获得lock锁");
}
}
}
}, "t-1"); Thread t2 = new Thread(new Runnable() { @Override
public void run() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ": 获得lock锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (map) {
System.out.println(Thread.currentThread().getName() + ": 获得map锁");
}
}
}
}, "t-2"); t.start();
t2.start();
} }
获取pid
假设当前不能直接连接27709虚拟机,需要使用参数-F
可以看出造成死锁的线程未t-1和t-2
使用jdb连接jvm
jdb -connect sun.jvm.hotspot.jdi.SAPIDAttachingConnector:pid=27709
执行threads命令获取所有线程列表
获取线程“t-1”堆栈信息,如下图,结合上述模拟死锁的代码,很容易就能看出来是哪里的问题
类似的,获取线程“t-2”的堆栈信息
通过以上步骤,基本上可以确定问题代码了。
本例也是匆忙中简单查看了下文档,没有详看,后续有时间在进行补充,jdb文档如下
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr011.html#BABDHAHJ