您好,登錄后才能下訂單哦!
本篇內容介紹了“Java中的工具Jstack怎么使用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
jstack - Prints Java thread stack traces for a Java process, core file, or remote debug server.
Jstack 主要的作用是生成當前進程中所有線程的信息,也就是當前時刻 JVM 的線程快照,通過線程的信息我們可以定位到程序中出現長時間停頓、CPU 占用率過高等問題。
線程快照中的信息是當前 java 虛擬機內每一條線程正在執行的方法的堆棧集合,有了堆棧信息我們就可以分析出我們的程序問題出現在那,比如線程間死鎖、外部資源請求時間過長、死循環等。
使用:
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 當正常的請求不被響應時,強制輸出堆棧信息。
-l 額外打印鎖的信息,當發生死鎖是可以查看鎖的信息
-m 如果調用本地方法棧的信息,可以打印 C/C++的堆棧
以一個發生死鎖的例子來看一下使用 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 的鎖,這樣就會發生死鎖。
先通過jps命令獲取到先拿到當前的進程 pid,然后通過 jstack 獲取線程的信息。可以看到有兩個線程都處于阻塞狀態。
"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)
第一行顯示可線程名、線程優先級、線程 id、線程狀態描述等信息
第二行顯示的是當前線程的狀態
Java 中線程的狀態分為 NEW、RUNNABLE、BLOCKED、WATING、TIMED_WATING、TERMINATED,但是在快照中 NEW 狀態是不會出現的。
再下面的就是當前線程的調用棧的信息。調用棧中包含了鎖的信息。
locked 表示使用 synchronized 申請對象鎖成功,監視器的擁有者
waiting to lock 表示使用 synchronized 申請對象鎖未成功,進入等待區。
waiting on 表示用 synchronized 申請對象鎖成功后,調用了 wait 方法,進入對象的等待區等待。
parking to wait for park 是基本的線程阻塞原語,不通過監視器在對象上阻塞。隨 concurrent 包會出現的新的機制,與 synchronized 體系不同。
在最后也顯示出了代碼中出現死鎖的信息
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,我們用一段死循環的代碼,通過 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 轉換為 16 進制
17997 -> 464d
4、使用 Jstack 查看 Java 所在的進程,并找到相應的線程
“Java中的工具Jstack怎么使用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。