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が配列の要素として返される。