文章
キャッチされない例外ハンドラ
UncaughtExceptionHandler は Thread API で提供されており、キャッチされない例外によるスレッドの終了を検出でき、スレッド リークを効果的に防止できます。キャッチされない例外によりスレッドが終了すると、JVM はこのイベントを UncaughtExceptionHandler 例外ハンドラに報告します。アプリケーションによって提供されます。
例外ハンドラーが提供されていない場合、デフォルトの動作では、シャトル トレース情報が System.err に出力されます。
UncaughtExceptionHandler ソース コード (JDK8)
/**
* 当线程由于未捕获异常而突然终止时调用的处理程序接口。
* 当线程由于未捕获异常即将终止时,Java虚拟机将使用getUncaughtExceptionHandler查询线程的
* UncaughtExceptionHandler,并调用处理程序的uncaughtException方法,将线程和异常作为参数传递。
* 如果线程未显式设置其UncaughtExceptionHandler,则其ThreadGroup对象将充当其
* UncaughtExceptionHandler。
* 如果ThreadGroup对象对处理异常没有特殊要求,它可以将调用转发给默认的未捕获异常处理程序。
*/
public interface UncaughtExceptionHandler {
/**
* 方法,该方法在给定线程由于给定的未捕获异常而终止时调用。
* Java虚拟机将忽略此方法引发的任何异常。
* 参数:
* t–线程
* e–异常
*/
void uncaughtException(Thread t, Throwable e);
}
例外ハンドラーがキャッチされなかった例外をどのように処理するかは、サービスの品質要件によって異なります。
最も一般的な対応は、エラー メッセージと対応するスタック トレースをアプリケーション ログに書き込むことです。
例外ハンドラーは、スレッドの再起動、アプリケーションのシャットダウン、またはその他の修復や診断の実行など、より即時的な応答を行うこともできます。
グアバ
次のコードは Guava (23.0) パッケージからのもので、参照できます。
package com.google.common.util.concurrent;
import static java.util.logging.Level.SEVERE;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Locale;
import java.util.logging.Logger;
/**
* Factories for {@link UncaughtExceptionHandler} instances.
*
* @author Gregory Kick
* @since 8.0
*/
@GwtIncompatible
public final class UncaughtExceptionHandlers {
private UncaughtExceptionHandlers() {
}
/**
* Returns an exception handler that exits the system. This is particularly useful for the main
* thread, which may start up other, non-daemon threads, but fail to fully initialize the
* application successfully.
*
* <p>Example usage:
*
* <pre>
* public static void main(String[] args) {
* Thread.currentThread().setUncaughtExceptionHandler(UncaughtExceptionHandlers.systemExit());
* ...
* </pre>
*
* <p>The returned handler logs any exception at severity {@code SEVERE} and then shuts down the
* process with an exit status of 1, indicating abnormal termination.
*/
public static UncaughtExceptionHandler systemExit() {
return new Exiter(Runtime.getRuntime());
}
@VisibleForTesting
static final class Exiter implements UncaughtExceptionHandler {
private static final Logger logger = Logger.getLogger(Exiter.class.getName());
private final Runtime runtime;
Exiter(Runtime runtime) {
this.runtime = runtime;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
try {
// cannot use FormattingLogger due to a dependency loop
logger.log(
SEVERE, String.format(Locale.ROOT, "Caught an exception in %s. Shutting down.", t), e);
} catch (Throwable errorInLogging) {
// If logging fails, e.g. due to missing memory, at least try to log the
// message and the cause for the failed logging.
System.err.println(e.getMessage());
System.err.println(errorInLogging.getMessage());
} finally {
runtime.exit(1);
}
}
}
}
要約する
長時間実行されるアプリケーションでは、すべてのスレッドからのキャッチされなかった例外に対して同じ例外ハンドラーを指定するのが一般的で、そのハンドラーは少なくとも例外情報を記録します。
スレッド プール内のすべてのスレッドに UncaughtExceptionHandler を設定するには、ThreadFactory を ThreadPoolExecutor のコンストラクターに提供します。(すべてのスレッド操作と同様、スレッド所有者のみがスレッドの UncaughtExceptionHandler を変更できます)
標準のスレッド プールでは、キャッチされなかった例外が発生したときにスレッドを終了できますが、通知を受け取るために try-finally コード ブロックが使用されるため、スレッドが終了すると、新しいスレッドがそれを置き換えます。
catch 例外ハンドラやその他の失敗通知メカニズムが提供されていない場合、タスクは何も通知せずに失敗し、大きな混乱を引き起こします。
例外によりタスクが失敗したときに通知を受け取り、タスク固有の回復操作を実行したい場合は、例外をキャッチできる Runnable または Callable でタスクをラップするか、ThreadPoolExecutor の afterExecute メソッドをオーバーライドします。
紛らわしいことに、execute
送信されたタスクのみが、スローした例外をキャッチされなかった例外ハンドラーに渡すことができ、送信submit
されたタスクは、スローされた非チェック例外であるかチェックされた例外であるかに関係なく、タスクの戻りステータスの一部とみなされます。
submit によって送信されたタスクが例外のスローにより終了した場合、例外は ExecutionException にラップされた Future.get によって再スローされます。
転載:https://blog.csdn.net/Shockang/article/details/121257329