Interstage Application Server チューニングガイド
目次 索引 前ページ次ページ

第8章 JDK/JREのチューニング> 8.3 チューニング/デバッグ技法

8.3.3 スレッドダンプ

 スレッドダンプには、Javaプロセスの各スレッドの情報(スタックトレース形式)が含まれているため、ハングアップやデッドロックなどの動作具合を調査することができます。

 スレッドダンプの出力先は、標準出力です。スレッドダンプが出力される契機および出力先を、表1に示します。

[表1 スレッドダンプの出力契機と出力先]

プログラムの種類

出力契機

出力先

J2EEアプリケーション

 アプリケーションがタイムアウトまたは無応答になった場合に自動採取されます。

コンテナ情報ログ(info.log)

J2EE以外のJavaプログラム


 コマンドプロンプトから、Javaプログラムを起動した場合、[Ctrl]+[Break]キー押下で採取することができます。
 また、“スレッドダンプツール”でも採取することができます。
 スレッドダンプツールの詳細は、“トラブルシューティング集”の“スレッドダンプツール”を参照してください。


 kill -QUIT [プロセスID]でJava VMに対してQUITシグナルを送ったときに採取することができます。

コンソール(標準出力)

 図1の出力例をもとにして、スレッドダンプの解析方法を説明します。

[図1 サンプルプログラム]

1 :public class DeadlockSample {
2 :    static boolean flag;
3 :    static Thread1 thread1;
4 :    static Thread2 thread2;
5 :
6 :    public static void main(String[] args) {
7 :        thread1 = new Thread1();
8 :        thread2 = new Thread2();
9 :        thread1.start();
10:        thread2.start();
11:    }
12:}
13:
14:class Thread1 extends Thread {
15:    public Thread1(){
16:        super("Thread1");
17:    }
18:
19:    public void run(){
20:        synchronized(this){
21:            System.out.println("Thread1開始");
22:            while(DeadlockSample.flag==false){  // Thread2が開始するのを待つ
23:                yield();
24:            }
25:            DeadlockSample.thread2.method();
26:            notify();
27:        }
28:    }
29:
30:    public synchronized void method(){
31:        try{wait(1000);}catch(InterruptedException ex){}
32:        System.out.println("Thread1.method()終了");
33:    }
34:}
35:
36:class Thread2 extends Thread {
37:    public Thread2(){
38:        super("Thread2");
39:    }
40:
41:    public void run() {
42:        synchronized(this){
43:            DeadlockSample.flag = true;
44:            System.out.println("Thread2開始");
45:            DeadlockSample.thread1.method();
46:            notify();
47:        }
48:    }
49:
50:    public synchronized void method() {
51:        try{wait(1000);}catch(InterruptedException ex){}
52:        System.out.println("Thread2.method()終了");
53:    }
54:}

 図1のサンプルでは、Thread1とThread2がお互いに排他処理を行っています。
 このサンプルを実行すると、次のように処理が進められます。

  1. Thread1で、Thread1のロックを獲得する(20行目のsynchronized節)
  2. Thread2で、Thread2のロックを獲得する(42行目のsynchronized節)
  3. Thread1で、Thread2.method()を実行しようとして、ロック解放待ちになる(50行目のsynchronized修飾子)
  4. Thread2で、Thread1.method()を実行しようとして、ロック解放待ちになる(50行目のsynchronized修飾子)

 この結果、Thead1とThread2がお互いに、解放されないロックを待ち続けるデッドロック状態になります。
 デッドロック状態で、スレッドダンプを採取したものを、図2に示します。

[図2 スレッドダンプ]

"DestroyJavaVM" prio=5 tid=0x002856c8 nid=0x5f4 waiting on condition [0..6fad8]

"Thread2" prio=5 tid=0x0092f4d8 nid=0x640 waiting for monitor entry [182ef000..182efd64]
at Thread1.method(DeadlockSample.java:31)
- waiting to lock <0x1002ffe8> (a Thread1)
at Thread2.run(DeadlockSample.java:45)
- locked <0x10030ca0> (a Thread2)
"Thread1" prio=5 tid=0x0092f370 nid=0x294 waiting for monitor entry [182af000..182afd64]
at Thread2.method(DeadlockSample.java:51)
- waiting to lock <0x10030ca0> (a Thread2)
at Thread1.run(DeadlockSample.java:25)
- locked <0x1002ffe8> (a Thread1)

"Signal Dispatcher" daemon prio=10 tid=0x0098eb80 nid=0x634 waiting on condition [0..0]

"Finalizer" daemon prio=9 tid=0x0092a540 nid=0x5e8 in Object.wait() [1816f000..1816fd64]
at java.lang.Object.wait(Native Method)
- waiting on <0x10010498> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:111)
- locked <0x10010498> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:127)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x0096da70 nid=0x5e4 in Object.wait() [1812f000..1812fd64]
at java.lang.Object.wait(Native Method)
- waiting on <0x10010388> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:429)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:115)
- locked <0x10010388> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=5 tid=0x0096c950 nid=0x624 runnable 

"VM Periodic Task Thread" prio=10 tid=0x0092c008 nid=0x2a0 waiting on condition 
"Suspend Checker Thread" prio=10 tid=0x0098e118 nid=0x478 runnable

Found one Java-level deadlock:
=============================
"Thread2":
  waiting to lock monitor 0x00929c3c (object 0x1002ffe8, a Thread1),
  which is held by "Thread1"
"Thread1":
  waiting to lock monitor 0x00929c5c (object 0x10030ca0, a Thread2),
  which is held by "Thread2"

Java stack information for the threads listed above:
===================================================
"Thread2":
at Thread1.method(DeadlockSample.java:31)
- waiting to lock <0x1002ffe8> (a Thread1)
at Thread2.run(DeadlockSample.java:45)
- locked <0x10030ca0> (a Thread2)
"Thread1":
at Thread2.method(DeadlockSample.java:51)
- waiting to lock <0x10030ca0> (a Thread2)
at Thread1.run(DeadlockSample.java:25)
- locked <0x1002ffe8> (a Thread1)

Found 1 deadlock.

■解析方法

 スレッドダンプの各スレッドの情報は、スタックトレース形式です。
 Thread1とThread2の両方のスタックトレースには、“locked”と“waiting to lock”があります。また、スレッドダンプの下の方にも、“deadlock”の文字列があり、デットロックが発生していることが確認できます。

 このように、スレッドダンプで全スレッドの動作状況を確認するにより、Javaプロセスがハングアップしているか、あるいは、デッドロック状態かを確認することができます。特に、短い間隔で複数のスレッドダンプを採取し、スレッドに動きがなければ、ハングアップの可能性があります。

 スレッドダンプの詳細は、“トラブルシューティング集”の“スレッドダンプが出力された場合の対処”も参照してください。


目次 索引 前ページ次ページ

All Rights Reserved, Copyright(C) 富士通株式会社 2007