在我们的应用程序中会应用到大量的多线程,然而在处理多线程程序时,如何获取线程的非正常终止(一般是遇到RuntimeException)是一件令人头疼的问题,因为线程池中的一个线程出现异常终止是很难发现的。本文给出两种方式用于感知多线程中的非正常终止
UncaughtExceptionHandler
在Thread类中存在一个UncaughtExceptionHandler接口用于处理未捕获的异常,当我们未设置该项时,其默认会将错误信息输出到System.err,通过实现该接口,我们可以自定义异常处理,用于记录或者恢复线程。要为线程池中的每一个线程设置UncaughtExceptionHandler,需要为ThreadPoolExecutor设置一个ThreadFactory,由ThreadFactory设置UncaughtExceptionHandler
示例:
static class LogUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName() + " ===> " + e);
}
}
public static void main(String[] args) {
ThreadFactory threadFactory = new ThreadFactoryBuilder().setUncaughtExceptionHandler(new LogUncaughtExceptionHandler()).build();
ExecutorService singleThread = new ThreadPoolExecutor(1, 1, 1L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10), threadFactory);
singleThread.execute(() -> {
System.out.println("ready to throws a exception");
throw new RuntimeException("Test!!!");
});
}
Output:
ready to throws a exception
pool-1-thread-1 ===> java.lang.RuntimeException: Test!!!
afterExecute
ThreadPoolExecutor中有一个afterExecutor方法,该方法有两个参数,Runnable和Throwable,当发生异常时,可以通过Throwable参数获取错误原因,通过重写该方法我们可以自定义线程非正常退出时的策略 示例:
static class MyThreadPoolExecutor extends ThreadPoolExecutor {
MyThreadPoolExecutor() {
super(1, 1, 1L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10), new ThreadPoolFactoryBuilder().build());
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
System.out.println(t == null);
}
}
public static void main(String[] args) {
ExecutorService threadPool = new MyThreadPoolExecutor();
threadPool.execute(() -> {
System.out.println("ready to throws a exception");
throw new RuntimeException("Test!!!");
});
}
Output:
ready to throws a exception
false
注:有一点需要注意的是,只有通过ExecutorService.execute方法才可以实现,而使用submit方法的话,无论是受检查异常还说运行时异常,都将被认为是任务返回状态的一部分