1. 程式人生 > >Java虛擬機器工具之堆疊跟蹤工具jstack檢測死鎖

Java虛擬機器工具之堆疊跟蹤工具jstack檢測死鎖

jstack是一個很實用的工具,不僅能定位到死迴圈的位置,還能找到死鎖的位置,這個工具對我們直接在生產機上定位錯誤帶來了極大的方便,尤其是那些不容易復現的錯誤。

首先呢,先寫一個能產生死鎖的程式碼。程式碼邏輯很簡單,咱就產生兩個執行緒,兩個執行緒分別執行加鎖與放鎖兩個動作,啥時候產生死鎖呢,就是在兩個執行緒都釋放鎖以後,又同時加鎖,於是互相僵持,互相等待,產生死鎖。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by Kevin on 11/4/16.
 */
class MultiThread implements Runnable{ private Object o1; private Object o2; private int flag; public MultiThread(Object o1, Object o2, int flag) { this.o1 = o1; this.o2 = o2; this.flag = flag; } public void task1() throws InterruptedException{ synchronized
(o1){ synchronized (o2){ System.out.println(Thread.currentThread().getName()); } } } public void task2() throws InterruptedException{ synchronized (o2){ Thread.yield(); synchronized (o1) { System.out.println(Thread.currentThread().getName()); } } } @Override
public void run() { while (true) { try { if (this.flag == 1) { this.task1(); } else { this.task2(); } } catch (InterruptedException e) { e.printStackTrace(); } } } } public class DeadLock { public static void main(String[] args){ Object o1 = new Object(); Object o2 = new Object(); ExecutorService executorService = Executors.newFixedThreadPool(10); for (int flag = 0; flag < 2; flag++) { executorService.execute(new MultiThread(o1, o2, flag)); } } }

執行程式碼,你會發現控制檯過一會兒就不動了,但是程式執行沒有終止,下面用jstack看看到底啥問題。

首先要找到該程序的pid

$ jps
11523 Main
27894 AppMain
27912 Launcher
27933 Jps
12046 JConsole

然後可以看到pid=27894,辣麼用jstack檢視一下27894:

$ jstack 27894
2016-11-07 14:59:55
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.101-b13 mixed mode):

"Attach Listener" #13 daemon prio=9 os_prio=0 tid=0x00007f5660001000 nid=0x6d3b runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"DestroyJavaVM" #12 prio=5 os_prio=0 tid=0x00007f569800a800 nid=0x6cf7 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"pool-1-thread-2" #11 prio=5 os_prio=0 tid=0x00007f5698156800 nid=0x6d07 waiting for monitor entry [0x00007f5684175000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at MultiThread.task1(DeadLock.java:21)
    - waiting to lock <0x00000000ec215b70> (a java.lang.Object)
    - locked <0x00000000ec215b60> (a java.lang.Object)
    at MultiThread.run(DeadLock.java:41)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

"pool-1-thread-1" #10 prio=5 os_prio=0 tid=0x00007f5698155000 nid=0x6d06 waiting for monitor entry [0x00007f5684276000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at MultiThread.task2(DeadLock.java:30)
    - waiting to lock <0x00000000ec215b60> (a java.lang.Object)
    - locked <0x00000000ec215b70> (a java.lang.Object)
    at MultiThread.run(DeadLock.java:43)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

"Monitor Ctrl-Break" #9 daemon prio=5 os_prio=0 tid=0x00007f5698152800 nid=0x6d05 runnable [0x00007f5684377000]
   java.lang.Thread.State: RUNNABLE
    at java.net.PlainSocketImpl.socketAccept(Native Method)
    at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
    at java.net.ServerSocket.implAccept(ServerSocket.java:545)
    at java.net.ServerSocket.accept(ServerSocket.java:513)
    at com.intellij.rt.execution.application.AppMain$1.run(AppMain.java:90)
    at java.lang.Thread.run(Thread.java:745)

"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x00007f56980da800 nid=0x6d03 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007f56980bd000 nid=0x6d02 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f56980bb800 nid=0x6d01 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f56980b8800 nid=0x6d00 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f56980b7000 nid=0x6cff runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f5698084000 nid=0x6cfe in Object.wait() [0x00007f5685682000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000ec188ee0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x00000000ec188ee0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f569807f800 nid=0x6cfd in Object.wait() [0x00007f5685783000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000ec186b50> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x00000000ec186b50> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"VM Thread" os_prio=0 tid=0x00007f5698078000 nid=0x6cfc runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f569801f800 nid=0x6cf8 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f5698021000 nid=0x6cf9 runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f5698023000 nid=0x6cfa runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f5698024800 nid=0x6cfb runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007f56980dd000 nid=0x6d04 waiting on condition 

JNI global references: 15


Found one Java-level deadlock:
=============================
"pool-1-thread-2":
  waiting to lock monitor 0x00007f56680062c8 (object 0x00000000ec215b70, a java.lang.Object),
  which is held by "pool-1-thread-1"
"pool-1-thread-1":
  waiting to lock monitor 0x00007f5668004e28 (object 0x00000000ec215b60, a java.lang.Object),
  which is held by "pool-1-thread-2"

Java stack information for the threads listed above:
===================================================
"pool-1-thread-2":
    at MultiThread.task1(DeadLock.java:21)
    - waiting to lock <0x00000000ec215b70> (a java.lang.Object)
    - locked <0x00000000ec215b60> (a java.lang.Object)
    at MultiThread.run(DeadLock.java:41)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
"pool-1-thread-1":
    at MultiThread.task2(DeadLock.java:30)
    - waiting to lock <0x00000000ec215b60> (a java.lang.Object)
    - locked <0x00000000ec215b70> (a java.lang.Object)
    at MultiThread.run(DeadLock.java:43)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock.

看到沒,其中有一段長這個模樣:

Found one Java-level deadlock:
=============================
"pool-1-thread-2":
  waiting to lock monitor 0x00007f56680062c8 (object 0x00000000ec215b70, a java.lang.Object),
  which is held by "pool-1-thread-1"
"pool-1-thread-1":
  waiting to lock monitor 0x00007f5668004e28 (object 0x00000000ec215b60, a java.lang.Object),
  which is held by "pool-1-thread-2"

Java stack information for the threads listed above:
===================================================
"pool-1-thread-2":
    at MultiThread.task1(DeadLock.java:21)
    ......
    at MultiThread.run(DeadLock.java:41)
    ......
    at MultiThread.task2(DeadLock.java:30)
    ......
    at MultiThread.run(DeadLock.java:43)
    ......

Found 1 deadlock.

人家說了這裡有死鎖,哪個檔案,第幾行都告你了,剩下的就自己去改吧。