HHeLiBeXの日記 正道編

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

java.lang.Thread.UncaughtExceptionHandler インタフェース

スレッドのエラーハンドリングためのインタフェース。


Interface for handlers invoked when a Thread abruptly terminates due to an uncaught exception.
関連するThreadクラスメソッド

public static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()
public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler()
public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

ちなみに、このインタフェースのメソッドと同じシグネチャメソッド自体は、ThreadGroupクラスにはJDK 1.0時代から存在している。(ThreadGroup (Java 2 Platform SE 5.0))


このインタフェースの用途としては、今のところはアプリケーション専用のログに記録するとかしか思いつかないのだが、とりあえず(謎)動きを見てみる。

System.out.println("default uncaught exception handler: " + Thread.getDefaultUncaughtExceptionHandler());
System.out.println("        uncaught exception handler: " + Thread.currentThread().getUncaughtExceptionHandler());
System.out.println("                      thread group: " + Thread.currentThread().getThreadGroup());

これをSunのJava VM(1.5.0_11)で実行すると、次のような出力が得られる。

default uncaught exception handler: null
        uncaught exception handler: java.lang.ThreadGroup[name=main,maxpri=10]
                      thread group: java.lang.ThreadGroup[name=main,maxpri=10]

デフォルトのハンドラーはなく、所属するThreadGroup自体がそのスレッドのハンドラーになっている。ThreadGroupクラスのuncaughtException()メソッドのソースを見てみると、

  • もし、親がいる場合は、親のuncaughtException()メソッドを呼ぶ。
  • そうでなければ、デフォルトのハンドラーを取得する。

という動作をする。例外が発生したときにコンソールに出力されるスタックトレースはこの動作によって出力されるもの。

ということは、デフォルトのハンドラーだけを設定する:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("[default][" + Thread.currentThread().getName() + "][" + t.getName() + "]");
    }
});
Thread thread1 = new Thread() {
    public void run() {
        throw new RuntimeException("test");
    }
};
thread1.start();

と、デフォルトのハンドラーが呼び出される:

[default][Thread-0][Thread-0]

し、個別のハンドラーを設定する:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("[default][" + Thread.currentThread().getName() + "][" + t.getName() + "]");
    }
});
Thread thread1 = new Thread() {
    public void run() {
        throw new RuntimeException("test");
    }
};
thread1.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("[ custom][" + Thread.currentThread().getName() + "][" + t.getName() + "]");
    }
});
thread1.start();

と、個別のハンドラーが呼び出される。

[ custom][Thread-0][Thread-0]

しかし、パラメータとして渡されるスレッドと、Thread.currentThread()メソッドで取得するスレッドは同じなのだから、パラメータで渡す意味は何だろう、と考えてしまう。