java堆棧跟蹤工具jstack的使用教程
1、jstack介紹
jstack(stack trace for java)是java虛擬機(jī)自帶的一種堆棧跟蹤工具。
jstack主要用于生成java虛擬機(jī)當(dāng)前時(shí)刻的線程快照,線程快照是當(dāng)前java虛擬機(jī)內(nèi)每一條線程正在執(zhí)行的方法堆棧的集合,生成線程快照的主要目的是定位線程出現(xiàn)長時(shí)間停頓的原因,如線程間死鎖、死循環(huán)、請求外部資源導(dǎo)致的長時(shí)間等待等。
線程出現(xiàn)停頓的時(shí)候通過jstack來查看各個(gè)線程的調(diào)用堆棧,就可以知道沒有響應(yīng)的線程到底在后臺做什么事情,或者等待什么資源。
jstack主要分為兩個(gè)功能:
- 針對活著的進(jìn)程做本地的或遠(yuǎn)程的線程dump
- 針對core文件做線程dump
當(dāng)指定的進(jìn)程在64位Java虛擬機(jī)上運(yùn)行時(shí),可能需要指定-J-d64選項(xiàng),例如:jstack -J-d64 -m pid。
2、線程狀態(tài)
線程通常有下面5中狀態(tài):
1、新建狀態(tài)(New): 新創(chuàng)建了一個(gè)線程對象。
2、就緒狀態(tài)(Runnable) :線程對象創(chuàng)建后,其他線程調(diào)用了該對象的start()方法。該狀態(tài)的線程位于可運(yùn)行線程池中,變得可運(yùn)行,等待獲取CPU的使用權(quán)。
3、運(yùn)行狀態(tài)(Running): 就緒狀態(tài)的線程獲取了CPU,執(zhí)行程序代碼。
4、阻塞狀態(tài)(Blocked): 阻塞狀態(tài)是線程因?yàn)槟撤N原因放棄CPU使用權(quán),暫時(shí)停止運(yùn)行。直到線程進(jìn)入就緒狀態(tài),才有機(jī)會轉(zhuǎn)到運(yùn)行狀態(tài)。阻塞的情況分三種:
等待阻塞:運(yùn)行的線程執(zhí)行wait()方法,JVM會把該線程放入等待池中。
同步阻塞:運(yùn)行的線程在獲取對象的同步鎖時(shí),若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池中。
其他阻塞:運(yùn)行的線程執(zhí)行sleep()或join()方法,或者發(fā)出了I/O請求時(shí),JVM會把該線程置為阻塞狀態(tài)。
當(dāng)sleep()狀態(tài)超時(shí)、join()等待線程終止或者超時(shí)、或者I/O處理完畢時(shí),線程重新轉(zhuǎn)入就緒狀態(tài)。
5、死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法,該線程結(jié)束生命周期。
關(guān)于線程狀態(tài),具體也可以查看:java.lang.Thread.State類。
想要通過jstack命令來分析線程的情況的話,首先要知道線程都有哪些狀態(tài),下面這些狀態(tài)是我們使用jstack命
令查看線程堆棧信息時(shí)可能會看到的線程的幾種狀態(tài):
- RUNNABLE,線程運(yùn)行中或I/O等待
- BLOCKED,線程被阻塞,在等待monitor鎖(synchronized關(guān)鍵字)
- TIMED_WAITING ,線程在等待喚醒,但設(shè)置了時(shí)限
- WAITING ,線程在無限等待喚醒
在線程的堆棧中,需要特別留意以下幾種狀態(tài):
- Deadlock: 死鎖(重點(diǎn)關(guān)注)
- Waiting on condition: 等待資源(重點(diǎn)關(guān)注)
- Waiting on monitor entry : 等待獲取監(jiān)視器(重點(diǎn)關(guān)注)
- Blocked :阻塞(重點(diǎn)關(guān)注)
- Runnable :執(zhí)行中
- Suspended : 暫停
- Object.wait()或TIME_WAITING :對象等待中
- Parked : 停止
3、jstack命令格式
jstack [ option ] pid
jstack [ option ] executable core
jstack [ option ] [server-id@]remote-hostname-or-IP
pid:Java進(jìn)程的ID,可以通過jps命令查詢到。
executable: 產(chǎn)生core dump的Java可執(zhí)行程序。
core:要打印的堆棧跟蹤的核心文件。
server-id:當(dāng)多個(gè)DEBUG服務(wù)器在同一遠(yuǎn)程主機(jī)上運(yùn)行時(shí),可使用的可選唯一ID。
remote-hostname-or-IP:遠(yuǎn)程DEBUG的服務(wù)器主機(jī)名或IP地址。
pid: 需要被打印配置信息的java進(jìn)程id,可以用jps查詢。
常用參數(shù)說明:
-F:當(dāng) jstack [-l] pid 沒有響應(yīng)時(shí),強(qiáng)制打印一個(gè)堆棧轉(zhuǎn)儲。
-l:打印關(guān)于鎖的其他信息,比如擁有的java.util.concurrent ownable同步器的列表,會使得JVM停頓得長久得多。
-m:打印包含Java和本機(jī)C/ C++幀的混合模式堆棧跟蹤。
-h:打印幫助信息。
-help:打印幫助信息。
3.1 jstack pid
第一行各個(gè)單詞的解析,
daemon:線程名稱 。
prio:線程優(yōu)先級
tid:指Java Thread id。
nid:指native線程的id。。
[0x000000002369e000]:線程棧起始地址。
3.2 死循環(huán)
package com.example.controller; public class Test2 { public static void main(String[] args) { while (true) { } } }
3.3 Object.wait()情況
package com.example.controller; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test3 { static class TestTask implements Runnable { @Override public void run() { synchronized (this) { try { //等待被喚醒 wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { ExecutorService ex = Executors.newFixedThreadPool(1); ex.execute(new TestTask()); } }
3.4 死鎖情況
package com.example.controller; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test4 { public static void main(String[] args) { Object obj1 = new Object(); Object obj2 = new Object(); ExecutorService ex = Executors.newFixedThreadPool(2); // 起10個(gè)線程 for (int i = 0; i < 10; i++) { int order = i % 2 == 0 ? 1 : 0; ex.execute(new TestTask(order, obj1, obj2)); } } static class TestTask implements Runnable { private Object obj1; private Object obj2; private int order; public TestTask(int order, Object obj1, Object obj2) { this.order = order; this.obj1 = obj1; this.obj2 = obj2; } public void test1() throws InterruptedException { synchronized (obj1) { synchronized (obj2) { System.out.println("test。。。"); } } } public void test2() throws InterruptedException { synchronized (obj2) { synchronized (obj1) { System.out.println("test。。。"); } } } @Override public void run() { while (true) { try { if (this.order == 1) { this.test1(); } else { this.test2(); } } catch (InterruptedException e) { e.printStackTrace(); } } } } }
3.5 等待io
package com.example.controller; import java.io.IOException; import java.io.InputStream; public class Test5 { public static void main(String[] args) throws IOException { InputStream is = System.in; int i = is.read(); System.out.println("exit。"); } }
以上就是java堆棧跟蹤工具jstack的使用教程的詳細(xì)內(nèi)容,更多關(guān)于java jstack的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java多線程之Future和FutureTask使用實(shí)例
這篇文章主要介紹了java多線程之Future和FutureTask使用實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09使用Java實(shí)現(xiàn)一個(gè)能保留計(jì)算過程的計(jì)算器
計(jì)算器是我們?nèi)粘I钪谐S玫墓ぞ咧?它能夠進(jìn)行基本的數(shù)學(xué)運(yùn)算,如加法、減法、乘法和除法,而在設(shè)計(jì)一個(gè)計(jì)算器時(shí),我們可以通過使用Java編程語言來實(shí)現(xiàn)一個(gè)簡單的控制臺計(jì)算器,并且讓它能夠保留計(jì)算過程,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-11-11Mybatis如何根據(jù)List批量查詢List結(jié)果
這篇文章主要介紹了Mybatis如何根據(jù)List批量查詢List結(jié)果,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03