如果程序掛死,有時使用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