Java中工具Jstack的使用實例
jstack - Prints Java thread stack traces for a Java process, core file, or remote debug server.
Jstack 主要的作用是生成當(dāng)前進程中所有線程的信息,也就是當(dāng)前時刻 JVM 的線程快照,通過線程的信息我們可以定位到程序中出現(xiàn)長時間停頓、CPU 占用率過高等問題。
線程快照中的信息是當(dāng)前 java 虛擬機內(nèi)每一條線程正在執(zhí)行的方法的堆棧集合,有了堆棧信息我們就可以分析出我們的程序問題出現(xiàn)在那,比如線程間死鎖、外部資源請求時間過長、死循環(huán)等。
使用:
jstack [ options ] pid
jstack [ options ] executable core
jstack [ options ] [ server-id@ ] remote-hostname-or-IP
OPTIONS
-F
Force a stack dump when jstack [-l] pid does not respond.
-l
Long listing. Prints additional information about locks such as a list of owned java.util.concurrent ownable synchronizers. See the
AbstractOwnableSynchronizer class description at
http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/AbstractOwnableSynchronizer.html
-m
Prints a mixed mode stack trace that has both Java and native C/C++ frames.- -F 當(dāng)正常的請求不被響應(yīng)時,強制輸出堆棧信息。
- -l 額外打印鎖的信息,當(dāng)發(fā)生死鎖是可以查看鎖的信息
- -m 如果調(diào)用本地方法棧的信息,可以打印 C/C++的堆棧
以一個發(fā)生死鎖的例子來看一下使用 Jstack 查看到的信息
public class Jstack {
private static Object obj1 = new Object();
private static Object obj2 = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (obj1) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj2) {
}
}
}).start();
new Thread(() -> {
synchronized (obj2) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj1) {
}
}
}).start();
}
}上面代碼中,第一個線程拿到 obj1 的鎖,等待 obj2 的鎖,第二個線程拿到 obj2 的鎖,等待 obj1 的鎖,這樣就會發(fā)生死鎖。
先通過jps命令獲取到先拿到當(dāng)前的進程 pid,然后通過 jstack 獲取線程的信息??梢钥吹接袃蓚€線程都處于阻塞狀態(tài)。
"Thread-1" #12 prio=5 os_prio=0 tid=0x00007fdff871c800 nid=0x3cc2 waiting for monitor entry [0x00007fdfce0fc000] java.lang.Thread.State: BLOCKED (on object monitor) at com.example.demo.jstack.Jstack.lambda$main$1(Jstack.java:36) - waiting to lock <0x000000076e925a90> (a java.lang.Object) - locked <0x000000076e925aa0> (a java.lang.Object) at com.example.demo.jstack.Jstack$$Lambda$2/2052001577.run(Unknown Source) at java.lang.Thread.run(Thread.java:748) "Thread-0" #11 prio=5 os_prio=0 tid=0x00007fdff871a800 nid=0x3cc1 waiting for monitor entry [0x00007fdfce1fc000] java.lang.Thread.State: BLOCKED (on object monitor) at com.example.demo.jstack.Jstack.lambda$main$0(Jstack.java:25) - waiting to lock <0x000000076e925aa0> (a java.lang.Object) - locked <0x000000076e925a90> (a java.lang.Object) at com.example.demo.jstack.Jstack$$Lambda$1/1174361318.run(Unknown Source) at java.lang.Thread.run(Thread.java:748)
第一行顯示可線程名、線程優(yōu)先級、線程 id、線程狀態(tài)描述等信息
第二行顯示的是當(dāng)前線程的狀態(tài)
? Java 中線程的狀態(tài)分為 NEW、RUNNABLE、BLOCKED、WATING、TIMED_WATING、TERMINATED,但是在快照中 NEW 狀態(tài)是不會出現(xiàn)的。
再下面的就是當(dāng)前線程的調(diào)用棧的信息。調(diào)用棧中包含了鎖的信息。
? locked 表示使用 synchronized 申請對象鎖成功,監(jiān)視器的擁有者
? waiting to lock 表示使用 synchronized 申請對象鎖未成功,進入等待區(qū)。
? waiting on 表示用 synchronized 申請對象鎖成功后,調(diào)用了 wait 方法,進入對象的等待區(qū)等待。
? parking to wait for park 是基本的線程阻塞原語,不通過監(jiān)視器在對象上阻塞。隨 concurrent 包會出現(xiàn)的新的機制,與 synchronized 體系不同。
在最后也顯示出了代碼中出現(xiàn)死鎖的信息
Found one Java-level deadlock: ============================= "Thread-1": waiting to lock monitor 0x00007fdfac006638 (object 0x000000076e925a90, a java.lang.Object), which is held by "Thread-0" "Thread-0": waiting to lock monitor 0x00007fdfac003da8 (object 0x000000076e925aa0, a java.lang.Object), which is held by "Thread-1" Java stack information for the threads listed above: =================================================== "Thread-1": at com.example.demo.jstack.Jstack.lambda$main$1(Jstack.java:36) - waiting to lock <0x000000076e925a90> (a java.lang.Object) - locked <0x000000076e925aa0> (a java.lang.Object) at com.example.demo.jstack.Jstack$$Lambda$2/2052001577.run(Unknown Source) at java.lang.Thread.run(Thread.java:748) "Thread-0": at com.example.demo.jstack.Jstack.lambda$main$0(Jstack.java:25) - waiting to lock <0x000000076e925aa0> (a java.lang.Object) - locked <0x000000076e925a90> (a java.lang.Object) at com.example.demo.jstack.Jstack$$Lambda$1/1174361318.run(Unknown Source) at java.lang.Thread.run(Thread.java:748) Found 1 deadlock.
好了,熟悉了 Jstack,我們用一段死循環(huán)的代碼,通過 Jstack 來定位到使 CPU 占用 100%的代碼行
public class JstackDemo {
public static Executor executor = Executors.newFixedThreadPool(3);
private static Object lock = new Object();
public static void main(String[] args) {
Task task1 = new Task();
Task task2 = new Task();
executor.execute(task1);
executor.execute(task2);
}
public static class Task implements Runnable {
@Override
public void run() {
synchronized (lock) {
run0();
}
}
private void run0() {
int i = 0;
while (true) {
i++;
}
}
}
}1、首先通過top查看到使 CPU 占用到 100%的進程 id

2、使用top -Hp 進程id 查看占用 CPU 最多的線程 id

3、將線程 id 轉(zhuǎn)換為 16 進制
17997 -> 464d
4、使用 Jstack 查看 Java 所在的進程,并找到相應(yīng)的線程

總結(jié)
到此這篇關(guān)于Java工具Jstack使用的文章就介紹到這了,更多相關(guān)Java工具Jstack使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java反射學(xué)習(xí) getClass()函數(shù)應(yīng)用
所謂反射,可以理解為在運行時期獲取對象類型信息的操作,本文將詳細介紹,需要的朋友可以參考下2012-12-12
maven引入本地jar包運行報錯java.lang.NoClassDefFoundError解決
這篇文章主要為大家介紹了maven引入本地jar包運行報錯java.lang.NoClassDefFoundError解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10
MyBatis-Flex實現(xiàn)多表聯(lián)查(自動映射)
我們可以輕松的使用 Mybaits-Flex 鏈接任何數(shù)據(jù)庫,本文主要介紹了MyBatis-Flex實現(xiàn)多表聯(lián)查(自動映射),具有一定的參考價值,感興趣的可以了解一下2024-06-06
spring-boot List轉(zhuǎn)Page的方法步驟
這篇文章主要介紹了spring-boot List轉(zhuǎn)Page的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
Spring的循環(huán)依賴、三級緩存解決方案源碼詳細解析
這篇文章主要介紹了Spring的循環(huán)依賴、三級緩存解決方案源碼詳細解析,在Spring中,由于IOC的控制反轉(zhuǎn),創(chuàng)建對象不再是簡單的new出來,而是交給Spring去創(chuàng)建,會經(jīng)歷一系列Bean的生命周期才創(chuàng)建出相應(yīng)的對象,需要的朋友可以參考下2024-01-01
使用Java實現(xiàn)Excel導(dǎo)入并進行數(shù)據(jù)校驗
這篇文章主要為大家詳細介紹了Java如何根據(jù)下載的指定數(shù)據(jù)模板寫入數(shù)據(jù)和導(dǎo)入并進行數(shù)據(jù)校驗,文中的示例代碼講解詳細,需要的可以了解下2025-03-03
IO流:java中解碼和編碼出現(xiàn)亂碼說明以及代碼實現(xiàn)方法
最近使用Java編寫一些讀取文件的小工具的時候,經(jīng)常與IO流打交道,但是自己對IO流的理解不是特別深刻,趁機整理下,這篇文章主要給大家介紹了關(guān)于IO流:java中解碼和編碼出現(xiàn)亂碼說明以及代碼實現(xiàn)的相關(guān)資料,需要的朋友可以參考下2023-11-11
Java超詳細精講數(shù)據(jù)結(jié)構(gòu)之bfs與雙端隊列
廣搜BFS的基本思想是: 首先訪問初始點v并將其標(biāo)志為已經(jīng)訪問。接著通過鄰接關(guān)系將鄰接點入隊。然后每訪問過一個頂點則出隊。按照順序,訪問每一個頂點的所有未被訪問過的頂點直到所有的頂點均被訪問過。廣度優(yōu)先遍歷類似與層次遍歷2022-07-07
鴻蒙中的設(shè)備權(quán)限管理與申請詳細示例代碼
在移動應(yīng)用開發(fā)中,權(quán)限管理是至關(guān)重要的一部分,尤其是在涉及用戶隱私或系統(tǒng)資源(如相機、位置、存儲等)的應(yīng)用中,這篇文章主要介紹了鴻蒙中的設(shè)備權(quán)限管理與申請的相關(guān)資料,需要的朋友可以參考下2025-08-08

