読者です 読者をやめる 読者になる 読者になる

HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

ThreadMXBean.findMonitorDeadlockedThreads() メソッド

前に書いた「java.lang.management パッケージ - ThreadMXBean インタフェース - HHeLiBeXの日記 正道編」の中の findMonitorDeadlockedThreads を、デッドロックを実際に発生させた後で情報出力してみる。

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;

public class Main {

    private static void log(String msg) {
        System.out.printf("%s [%2d][%-8s] %s\n",
                Thread.currentThread().getId(),
                Thread.currentThread().getName(),
                msg);
    }

    /**
     * 一つ目のロックを取得した後で5秒スリープし、
     * その後、二つ目のロックを取得し、
     * interruptされるまでスリープし続ける。
     */
    private static class DoubleLockThread extends Thread {

        private Object lock1;
        private Object lock2;

        public DoubleLockThread(String name, Object lock1, Object lock2) {
            super(name);

            this.lock1 = lock1;
            this.lock2 = lock2;
        }

        public void run() {
            log("start run()");
            try {
                log("try to get lock " + lock1);
                synchronized (lock1) {
                    log("success to get lock " + lock1);
                    Thread.sleep(5000);
                    log("try to get lock " + lock2);
                    synchronized (lock2) {
                        log("success to get lock " + lock2);
                        while (true) {
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                log("sleep(1000) interrupted");
                                break;
                            }
                        }
                        log("going to release lock " + lock2);
                    }
                    log("released lock " + lock2);
                    log("going to release lock " + lock1);
                }
                log("released lock " + lock1);
            } catch (InterruptedException e) {
                log("sleep(5000) interrupted");
                e.printStackTrace(System.out);
            }
            log("end run()");
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.printf("%-23s = %s\n", "java.version", System.getProperty("java.version"));
        System.out.printf("%-23s = %s\n", "java.vendor", System.getProperty("java.vendor"));
        System.out.printf("%-23s = %s\n", "java.runtime.version", System.getProperty("java.runtime.version"));
        System.out.printf("%-23s = %s\n", "os.name", System.getProperty("os.name"));

        System.out.println("========");

        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();

        printFindMonitorDeadlockedThreads(threadMXBean);

        Object lock1 = new Object() { public String toString() { return "LOCK-1"; } };
        Object lock2 = new Object() { public String toString() { return "LOCK-2"; } };

        Thread th1 = new DoubleLockThread("TH-1", lock1, lock2);
        Thread th2 = new DoubleLockThread("TH-2", lock2, lock1);

        th1.start();
        th2.start();

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        log("try to interrupt both th-1 and th-2");
        th1.interrupt();
        th2.interrupt();
        log("interrupted both th-1 and th-2");

        printFindMonitorDeadlockedThreads(threadMXBean);
    }

    private static void printFindMonitorDeadlockedThreads(ThreadMXBean threadMXBean) {
        System.out.printf("%-32s:\n", "findMonitorDeadlockedThreads");
        {
            long[] monitorDeadlockedThreads = threadMXBean.findMonitorDeadlockedThreads();
            if (monitorDeadlockedThreads != null) {
                System.out.printf("    %-32s: %10d\n", "# of threads", monitorDeadlockedThreads.length);

                int i = 0;
                for (long id : monitorDeadlockedThreads) {
                    System.out.printf("    [%2d]: %20d\n", i, id);
    
                    ++i;
                }
            }
        }
    }

}

使用しているコードは、基本的には「Threadはinterruptすれば停止するというものではないのだよ(2) - HHeLiBeXの日記 正道編」と同じなので説明は省略。
実行結果。

java.version            = 1.5.0_11
java.vendor             = Sun Microsystems Inc.
java.runtime.version    = 1.5.0_11-b03
os.name                 = Windows Vista
========
findMonitorDeadlockedThreads    :
[ 7][TH-1    ] start run()
[ 7][TH-1    ] try to get lock LOCK-1
[ 7][TH-1    ] success to get lock LOCK-1
[ 8][TH-2    ] start run()
[ 8][TH-2    ] try to get lock LOCK-2
[ 8][TH-2    ] success to get lock LOCK-2
[ 7][TH-1    ] try to get lock LOCK-2
[ 8][TH-2    ] try to get lock LOCK-1
[ 1][main    ] try to interrupt both th-1 and th-2
[ 1][main    ] interrupted both th-1 and th-2
findMonitorDeadlockedThreads    :
    # of threads                    :          2
    [ 0]:                    8
    [ 1]:                    7

スレッド開始前はデッドロックしているスレッドがないので、「ThreadMXBean.findMonitorDeadlockedThreads()」の戻り値はnullなのだが、デッドロックを発生させると、対象のスレッドIDが配列の要素として返される。