Java如何通過jstack命令查詢?nèi)罩?/h1>
更新時(shí)間:2023年03月21日 14:54:33 作者:吳名氏
在分析線上問題時(shí)常使用到j(luò)stack?<PID>命令將當(dāng)時(shí)Java應(yīng)用程序的線程堆棧dump出來(lái),面對(duì)jstack?日志,我們?nèi)绾尾榭??下面小編給大家介紹下Java如何通過jstack命令查詢?nèi)罩?,感興趣的朋友一起看看吧
在分析線上問題時(shí)常使用到j(luò)stack <PID>命令將當(dāng)時(shí)Java應(yīng)用程序的線程堆棧dump出來(lái)。
面對(duì)jstack 日志,我們?nèi)绾尾榭矗?/p>
1 首先要清楚線程的狀態(tài)
線程的狀態(tài)有: new、runnable、running、waiting、timed_waiting、blocked、dead
1.1 線程狀態(tài)變遷圖:

1.2 各狀態(tài)說明:
New: 當(dāng)線程對(duì)象創(chuàng)建時(shí)存在的狀態(tài),此時(shí)線程不可能執(zhí)行;
Runnable:當(dāng)調(diào)用thread.start()后,線程變成為Runnable狀態(tài)。只要得到CPU,就可以執(zhí)行;
Running:線程正在執(zhí)行;
Waiting:執(zhí)行thread.join()或在鎖對(duì)象調(diào)用obj.wait()等情況就會(huì)進(jìn)該狀態(tài),表明線程正處于等待某個(gè)資源或條件發(fā)生來(lái)喚醒自己;
Timed_Waiting:執(zhí)行Thread.sleep(long)、thread.join(long)或obj.wait(long)等就會(huì)進(jìn)該狀態(tài),與Waiting的區(qū)別在于Timed_Waiting的等待有時(shí)間限制;
Blocked:如果進(jìn)入同步方法或同步代碼塊,沒有獲取到鎖,則會(huì)進(jìn)入該狀態(tài);
Dead:線程執(zhí)行完畢,或者拋出了未捕獲的異常之后,會(huì)進(jìn)入dead狀態(tài),表示該線程結(jié)束
1.3 對(duì)于jstack日志,我們要著重關(guān)注如下關(guān)鍵信息
Deadlock:表示有死鎖
Waiting on condition:等待某個(gè)資源或條件發(fā)生來(lái)喚醒自己。具體需要結(jié)合jstacktrace來(lái)分析,比如線程正在sleep,網(wǎng)絡(luò)讀寫繁忙而等待
Blocked:阻塞
Waiting on monitor entry:在等待獲取鎖
in Object.wait():獲取鎖后又執(zhí)行obj.wait()放棄鎖
1.4 Waiting on monitor entry 和 in Object.wait()的詳細(xì)描述
Monitor是 Java中用以實(shí)現(xiàn)線程之間的互斥與協(xié)作的主要手段,它可以看成是對(duì)象或者 Class的鎖。每一個(gè)對(duì)象都有,也僅有一個(gè) monitor。從下圖中可以看出,每個(gè) Monitor在某個(gè)時(shí)刻,只能被一個(gè)線程擁有,該線程就是 "Active Thread",而其它線程都是 "Waiting Thread",分別在兩個(gè)隊(duì)列 " Entry Set"和 "Wait Set"里面等候。在 "Entry Set"中等待的線程狀態(tài)是 "Waiting for monitor entry",而在 "Wait Set"中等待的線程狀態(tài)是 "in Object.wait()"
2 舉例說明
2.1 blocked 的例子

程序先輸出main,在輸出thread,說明mian的線程是先獲得同步鎖的
執(zhí)行jstack pid輸出信息如下:


可以看到thread1在進(jìn)行等待獲取到鎖,此時(shí)進(jìn)入waiting for monitor entry,并是阻塞狀態(tài)。
而main線程提前獲取到鎖,當(dāng)由于調(diào)用了sleep此時(shí)進(jìn)入到Timed_waiting狀態(tài),此時(shí)man線程鎖住的對(duì)象地址是7f3167cf0,而thread1正在等待獲取這個(gè)鎖對(duì)象。
prio:線程的優(yōu)先級(jí)
tid:線程id
nid:操作系統(tǒng)映射的線程id, 非常關(guān)鍵,后面再使用jstack時(shí)補(bǔ)充
1103e9000和106692000 :表示線程棧的起始地址。
從jstack日志中,可以看到:主線程獲取到thread2對(duì)象上的鎖,因此正在執(zhí)行sleep操作,狀態(tài)為TIMED_WAINTING, 而thread2由于未獲取到thread2對(duì)象上的鎖,因此處于BLOCKED狀態(tài)。
再細(xì)看,thread2 正在"waiting to lock <7f3167cf0>",即試圖在地址為7f3167cf0所在的對(duì)象獲取鎖,而該鎖卻被main線程占有(locked <7f3167cf0>)。main線程正在"waiting on condition",說明正在等待某個(gè)條件觸發(fā),由jstacktrace來(lái)看,此線程正在sleep。
經(jīng)驗(yàn):
如果在jstack日志發(fā)現(xiàn)大量的線程在waiting to lock 某個(gè)地址,只要能查到哪個(gè)線程獲取到鎖就可以方便定位問題了
2.2 object.wait()
public static void main(String[] args) {
final Thread thread = new Thread() {
@Override
public void run() {
synchronized (this) {
System.out.println(Thread.currentThread().getName());
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
thread.start();
thread.setName("zouxh");//起名字,方便在線程棧里面進(jìn)行查看
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (thread) {
System.out.println(Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
thread.notify();
}
}
執(zhí)行后,查看jstack的日志如下:
"zouxh" prio=5 tid=7fe18c97b800 nid=0x115e58000 in Object.wait() [115e57000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <7f3112fe8> (a jstat.MainWati$1)
at java.lang.Object.wait(Object.java:485)
at jstat.MainWati$1.run(MainWati.java:16)
- locked <7f3112fe8> (a jstat.MainWati$1)
"main" prio=5 tid=7fe18c000800 nid=0x10c47b000
waiting on condition [10c47a000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:300)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:328)
at jstat.MainWati.main(MainWati.java:37)
- locked <7f3112fe8> (a jstat.MainWati$1)
可以看到由于調(diào)用了object.wait()方法的時(shí)候放棄了鎖,所以zouxh這個(gè)線程就出現(xiàn)了object.wait()狀態(tài),線程的狀態(tài)就是waiting,等待notify來(lái)進(jìn)行喚醒。
由于mian線程在獲得zouxh的線程鎖后,調(diào)用了sleep方法,所以此時(shí)進(jìn)入了wating on condition等待某一個(gè)資源,進(jìn)入到time_waiting狀態(tài)。
2.3 waiting on conditon
private static BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(1);
public static void main(String[] args) {
blockingQueue.add("zouxh");
try {
//阻塞的添加
blockingQueue.put("ssss");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
線程棧如下:
"main" prio=5 tid=7f8f65000800 nid=0x10d7bb000 waiting on condition [10d7ba000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <7f3110d80> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
at java.util.concurrent.ArrayBlockingQueue.put(ArrayBlockingQueue.java:257)
at jstat.WatingTest.main(WatingTest.java:13)
此時(shí)main線程進(jìn)入了waiting on conditon狀態(tài),等待某一個(gè)資源,此時(shí)可以看到是在
a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObjec進(jìn)行了等待,阻塞住了,這是由于put發(fā)生了阻塞。
3 總結(jié)
對(duì)于jstack日志,我們要著重關(guān)注如下關(guān)鍵信息
Deadlock:表示有死鎖
Waiting on condition:等待某個(gè)資源或條件發(fā)生來(lái)喚醒自己。具體需要結(jié)合jstacktrace來(lái)分析,比如線程正在sleep,網(wǎng)絡(luò)讀寫繁忙而等待
Blocked:阻塞
Waiting on monitor entry:在等待獲取鎖
如果說系統(tǒng)慢,那么要特別關(guān)注Blocked,Waiting on condition
如果說系統(tǒng)的cpu耗的高,那么肯定是線程執(zhí)行有死循環(huán),那么此時(shí)要關(guān)注下Runable狀態(tài)。
到此這篇關(guān)于java通過jstack命令查詢?nèi)罩镜奈恼戮徒榻B到這了,更多相關(guān)java jstack命令查詢?nèi)罩緝?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
-
深入Java Robot實(shí)現(xiàn)控制鼠標(biāo)和鍵盤的方法詳解
本篇文章是對(duì)Java中用Robot實(shí)現(xiàn)控制鼠標(biāo)和鍵盤的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下 2013-05-05
-
JAVA錯(cuò)誤:'無(wú)效目標(biāo)發(fā)行版?17'的解決方案
這篇文章主要給大家介紹了關(guān)于JAVA錯(cuò)誤:'無(wú)效目標(biāo)發(fā)行版?17'的解決方案,文中通過圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或使用java具有一的的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下 2022-09-09
-
DOM解析XML報(bào)錯(cuò)Content is not allowed in prolog解決方案詳解
這篇文章主要介紹了DOM解析XML報(bào)錯(cuò)解決方案詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下 2020-10-10
-
Springboot+Poi導(dǎo)入Excel表格實(shí)現(xiàn)過程詳解
這篇文章主要介紹了Springboot+Poi導(dǎo)入Excel表格實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下 2020-09-09
最新評(píng)論
在分析線上問題時(shí)常使用到j(luò)stack <PID>命令將當(dāng)時(shí)Java應(yīng)用程序的線程堆棧dump出來(lái)。
面對(duì)jstack 日志,我們?nèi)绾尾榭矗?/p>
1 首先要清楚線程的狀態(tài)
線程的狀態(tài)有: new、runnable、running、waiting、timed_waiting、blocked、dead
1.1 線程狀態(tài)變遷圖:
1.2 各狀態(tài)說明:
New: 當(dāng)線程對(duì)象創(chuàng)建時(shí)存在的狀態(tài),此時(shí)線程不可能執(zhí)行;
Runnable:當(dāng)調(diào)用thread.start()后,線程變成為Runnable狀態(tài)。只要得到CPU,就可以執(zhí)行;
Running:線程正在執(zhí)行;
Waiting:執(zhí)行thread.join()或在鎖對(duì)象調(diào)用obj.wait()等情況就會(huì)進(jìn)該狀態(tài),表明線程正處于等待某個(gè)資源或條件發(fā)生來(lái)喚醒自己;
Timed_Waiting:執(zhí)行Thread.sleep(long)、thread.join(long)或obj.wait(long)等就會(huì)進(jìn)該狀態(tài),與Waiting的區(qū)別在于Timed_Waiting的等待有時(shí)間限制;
Blocked:如果進(jìn)入同步方法或同步代碼塊,沒有獲取到鎖,則會(huì)進(jìn)入該狀態(tài);
Dead:線程執(zhí)行完畢,或者拋出了未捕獲的異常之后,會(huì)進(jìn)入dead狀態(tài),表示該線程結(jié)束
1.3 對(duì)于jstack日志,我們要著重關(guān)注如下關(guān)鍵信息
Deadlock:表示有死鎖
Waiting on condition:等待某個(gè)資源或條件發(fā)生來(lái)喚醒自己。具體需要結(jié)合jstacktrace來(lái)分析,比如線程正在sleep,網(wǎng)絡(luò)讀寫繁忙而等待
Blocked:阻塞
Waiting on monitor entry:在等待獲取鎖
in Object.wait():獲取鎖后又執(zhí)行obj.wait()放棄鎖
1.4 Waiting on monitor entry 和 in Object.wait()的詳細(xì)描述
Monitor是 Java中用以實(shí)現(xiàn)線程之間的互斥與協(xié)作的主要手段,它可以看成是對(duì)象或者 Class的鎖。每一個(gè)對(duì)象都有,也僅有一個(gè) monitor。從下圖中可以看出,每個(gè) Monitor在某個(gè)時(shí)刻,只能被一個(gè)線程擁有,該線程就是 "Active Thread",而其它線程都是 "Waiting Thread",分別在兩個(gè)隊(duì)列 " Entry Set"和 "Wait Set"里面等候。在 "Entry Set"中等待的線程狀態(tài)是 "Waiting for monitor entry",而在 "Wait Set"中等待的線程狀態(tài)是 "in Object.wait()"
2 舉例說明
2.1 blocked 的例子
程序先輸出main,在輸出thread,說明mian的線程是先獲得同步鎖的
執(zhí)行jstack pid輸出信息如下:
可以看到thread1在進(jìn)行等待獲取到鎖,此時(shí)進(jìn)入waiting for monitor entry,并是阻塞狀態(tài)。
而main線程提前獲取到鎖,當(dāng)由于調(diào)用了sleep此時(shí)進(jìn)入到Timed_waiting狀態(tài),此時(shí)man線程鎖住的對(duì)象地址是7f3167cf0,而thread1正在等待獲取這個(gè)鎖對(duì)象。
prio:線程的優(yōu)先級(jí)
tid:線程id
nid:操作系統(tǒng)映射的線程id, 非常關(guān)鍵,后面再使用jstack時(shí)補(bǔ)充
1103e9000和106692000 :表示線程棧的起始地址。
從jstack日志中,可以看到:主線程獲取到thread2對(duì)象上的鎖,因此正在執(zhí)行sleep操作,狀態(tài)為TIMED_WAINTING, 而thread2由于未獲取到thread2對(duì)象上的鎖,因此處于BLOCKED狀態(tài)。
再細(xì)看,thread2 正在"waiting to lock <7f3167cf0>",即試圖在地址為7f3167cf0所在的對(duì)象獲取鎖,而該鎖卻被main線程占有(locked <7f3167cf0>)。main線程正在"waiting on condition",說明正在等待某個(gè)條件觸發(fā),由jstacktrace來(lái)看,此線程正在sleep。
經(jīng)驗(yàn):
如果在jstack日志發(fā)現(xiàn)大量的線程在waiting to lock 某個(gè)地址,只要能查到哪個(gè)線程獲取到鎖就可以方便定位問題了
2.2 object.wait()
public static void main(String[] args) { final Thread thread = new Thread() { @Override public void run() { synchronized (this) { System.out.println(Thread.currentThread().getName()); try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; thread.start(); thread.setName("zouxh");//起名字,方便在線程棧里面進(jìn)行查看 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (thread) { System.out.println(Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(30); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } thread.notify(); } }
執(zhí)行后,查看jstack的日志如下:
"zouxh" prio=5 tid=7fe18c97b800 nid=0x115e58000 in Object.wait() [115e57000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <7f3112fe8> (a jstat.MainWati$1)
at java.lang.Object.wait(Object.java:485)
at jstat.MainWati$1.run(MainWati.java:16)
- locked <7f3112fe8> (a jstat.MainWati$1)
"main" prio=5 tid=7fe18c000800 nid=0x10c47b000
waiting on condition [10c47a000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:300)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:328)
at jstat.MainWati.main(MainWati.java:37)
- locked <7f3112fe8> (a jstat.MainWati$1)
可以看到由于調(diào)用了object.wait()方法的時(shí)候放棄了鎖,所以zouxh這個(gè)線程就出現(xiàn)了object.wait()狀態(tài),線程的狀態(tài)就是waiting,等待notify來(lái)進(jìn)行喚醒。
由于mian線程在獲得zouxh的線程鎖后,調(diào)用了sleep方法,所以此時(shí)進(jìn)入了wating on condition等待某一個(gè)資源,進(jìn)入到time_waiting狀態(tài)。
2.3 waiting on conditon
private static BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(1); public static void main(String[] args) { blockingQueue.add("zouxh"); try { //阻塞的添加 blockingQueue.put("ssss"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
線程棧如下:
"main" prio=5 tid=7f8f65000800 nid=0x10d7bb000 waiting on condition [10d7ba000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <7f3110d80> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
at java.util.concurrent.ArrayBlockingQueue.put(ArrayBlockingQueue.java:257)
at jstat.WatingTest.main(WatingTest.java:13)
此時(shí)main線程進(jìn)入了waiting on conditon狀態(tài),等待某一個(gè)資源,此時(shí)可以看到是在
a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObjec進(jìn)行了等待,阻塞住了,這是由于put發(fā)生了阻塞。
3 總結(jié)
對(duì)于jstack日志,我們要著重關(guān)注如下關(guān)鍵信息
Deadlock:表示有死鎖
Waiting on condition:等待某個(gè)資源或條件發(fā)生來(lái)喚醒自己。具體需要結(jié)合jstacktrace來(lái)分析,比如線程正在sleep,網(wǎng)絡(luò)讀寫繁忙而等待
Blocked:阻塞
Waiting on monitor entry:在等待獲取鎖
如果說系統(tǒng)慢,那么要特別關(guān)注Blocked,Waiting on condition
如果說系統(tǒng)的cpu耗的高,那么肯定是線程執(zhí)行有死循環(huán),那么此時(shí)要關(guān)注下Runable狀態(tài)。
到此這篇關(guān)于java通過jstack命令查詢?nèi)罩镜奈恼戮徒榻B到這了,更多相關(guān)java jstack命令查詢?nèi)罩緝?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入Java Robot實(shí)現(xiàn)控制鼠標(biāo)和鍵盤的方法詳解
本篇文章是對(duì)Java中用Robot實(shí)現(xiàn)控制鼠標(biāo)和鍵盤的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05JAVA錯(cuò)誤:'無(wú)效目標(biāo)發(fā)行版?17'的解決方案
這篇文章主要給大家介紹了關(guān)于JAVA錯(cuò)誤:'無(wú)效目標(biāo)發(fā)行版?17'的解決方案,文中通過圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或使用java具有一的的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-09-09DOM解析XML報(bào)錯(cuò)Content is not allowed in prolog解決方案詳解
這篇文章主要介紹了DOM解析XML報(bào)錯(cuò)解決方案詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10Springboot+Poi導(dǎo)入Excel表格實(shí)現(xiàn)過程詳解
這篇文章主要介紹了Springboot+Poi導(dǎo)入Excel表格實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09