スレッドの例外補足
なんか、スレッドの異常系のテストをしたいなーと思ったら、スレッドってほとんどやったことなかったので、けっこうてこずりました。
以下のTest001を実行しても、exeメソッドの中でRuntimeExceptionがキャッチできない。
public class Test001 { public static void main(String[] args) throws Exception { new Test001().exe(); } private void exe() throws Exception { System.out.println("START"); MyThread thread = new MyThread(); try { thread.start(); thread.join(); } catch (Throwable e) { System.out.println("exeメソッド内でキャッチ : " + e); throw e; } System.out.println("END"); } // スレッド class MyThread extends Thread { public void run() { if(true) throw new RuntimeException(this.getName()); } } }
実行結果
START END
スレッド内の例外をスレッド呼び出し元でキャッチする場合は、JDK1.4以下はThreadGroupのサブクラスを作る必要があるみたい。
public class Test001 { public static void main(String[] args) throws Exception { new Test001().exe(); } private void exe() throws Exception { System.out.println("START"); MyThreadGroup threadGroup = new MyThreadGroup("MyThreadGroup"); MyThread thread = new MyThread(threadGroup, "MyThreadGroup"); thread.start(); thread.join(); if (threadGrpup.getThrowable() != null) { System.out.println("exeメソッド内でキャッチ : " + threadGrpup.getThrowable()); } System.out.println("END"); } // スレッド class MyThread extends Thread { public MyThread(ThreadGroup threadGroup, String name) { super(threadGroup, name); } public void run() { if(true) throw new RuntimeException(this.getName()); } } // スレッドグループ class MyThreadGroup extends ThreadGroup { private Throwable throwable = null; public MyThreadGroup(String name) { super(name); } public void uncaughtException(Thread t, Throwable e) { throwable = e; } public Throwable getThrowable() { return throwable; } } }
これで実行結果は以下のようになりました。
START exeメソッド内でキャッチ : java.lang.RuntimeException: MyThreadGroup END
Thread.join()で子スレッド終了を待ち、スレッドグループがなくなるので、以下のようになります。
thread.join();の前ならthread.getThreadGroup()でThreadGroupインスタンスが取得できるけど、
thread.join();の後だとthread.getThreadGroup()を呼び出してもnullです。
JDK1.5以上はこんな感じかなー。
public class Test001 { public static void main(String[] args) throws Exception { new Test001().exe(); } private void exe() throws Exception { System.out.println("START"); MyThread thread = new MyThread(); MyUncaughtExceptionHandler handler = new MyUncaughtExceptionHandler(); thread.setUncaughtExceptionHandler(handler); thread.start(); thread.join(); System.out.println("exeメソッド内でキャッチ : " + handler.getThrowable()); System.out.println("END"); } class MyThread extends Thread { public void run() { if(true) throw new RuntimeException(this.getName()); } } class MyUncaughtExceptionHandler implements UncaughtExceptionHandler { private Throwable throwable = null; public void uncaughtException(Thread t, Throwable e) { throwable = e; } public Throwable getThrowable() { return throwable; } } }
これで実行結果は以下のようになりました。
START exeメソッド内でキャッチ : java.lang.RuntimeException: Thread-0 END
Thread.join()で子スレッド終了を待ち、スレッドグループがなくなるので、以下のようになります。
thread.join();の前ならthread.getUncaughtExceptionHandler()でMyUncaughtExceptionHandlerインスタンスが取得できるけど、
thread.join();の後だとthread.getUncaughtExceptionHandler()を呼び出してもnullです。