提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、UncaughtExceptionHandler 是什么?
- 二、使用步骤
- 1.通过try-catch捕捉子线程的问题
- 2.非线程池设置
- 3.线程池的情况下设置UncaughtExceptionHandler
- 总结
前言
前些天,在网上逛论坛的时候看到 UncaughtExceptionHandler ,貌似从来没用过,所以学习下
一、UncaughtExceptionHandler 是什么?
/*** 当线程由于未捕获异常而突然终止时调用的处理程序接口。 * 当线程由于未捕获异常即将终止时,Java虚拟机将使用getUncaughtExceptionHandler查询线程的* UncaughtExceptionHandler,并调用处理程序的uncaughtException方法,将线程和异常作为参数传递。* 如果线程未显式设置其UncaughtExceptionHandler,则其ThreadGroup对象将充当其* UncaughtExceptionHandler。* 如果ThreadGroup对象对处理异常没有特殊要求,它可以将调用转发给默认的未捕获异常处理程序。*/
public interface UncaughtExceptionHandler {/*** 方法,该方法在给定线程由于给定的未捕获异常而终止时调用。 * Java虚拟机将忽略此方法引发的任何异常。 * 参数: * t–线程 * e–异常*/void uncaughtException(Thread t, Throwable e);}
这个描述看取来 就是给程序员一个钩子函数,让程序可以感知到线程非正常关闭时的情况,可以打日志 或者 啥操作
二、使用步骤
1.通过try-catch捕捉子线程的问题
public class Test {public static void main(String[] args) {try {Thread thread = new Thread(new Task());thread.start();} catch (Exception e) {System.out.println("==Exception: " + e.getMessage());}}
}class Task implements Runnable {@Overridepublic void run() {System.out.println(1 / 0);}
}
输出
Exception in thread "Thread-0" java.lang.ArithmeticException: / by zeroat com.example.demo.config.Task.run(ttt.java:33)at java.lang.Thread.run(Thread.java:745)
可以看到,其实catch 并未捕捉到 异常,而子线程的错误 抛出到虚拟机了
2.非线程池设置
通过设置线程的UncaughtExceptionHandler 则可以捕捉到异常
public class Test {public static void main(String args[]) {Thread thread = new Thread(new Task());thread.setUncaughtExceptionHandler(new ExceptionHandlerDemo());thread.start();}
}class ExceptionHandlerDemo implements Thread.UncaughtExceptionHandler {@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println("whp Exception: " + e.getMessage());}
}class Task implements Runnable {@Overridepublic void run() {System.out.println(1 / 0);}
}输出:
whp Exception: / by zero
3.线程池的情况下设置UncaughtExceptionHandler
public class testClass {public static void main(String[] args) throws ExecutionException, InterruptedException {ThreadPoolTaskExecutor executorService = buildThreadPoolTaskExecutor();//这里注意先是execute ,如果是submit 则有些不同 需要get 才能出现错误executorService.execute(() -> run("execute方法"));}private static void run(String name) {String printStr = "【thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name+"】";System.out.println(printStr);throw new RuntimeException(printStr + ",出现异常");}private static ThreadPoolTaskExecutor buildThreadPoolTaskExecutor() {ThreadPoolTaskExecutor executorService = new ThreadPoolTaskExecutor();executorService.setCorePoolSize(5);executorService.setMaxPoolSize(5);executorService.setQueueCapacity(10);executorService.setKeepAliveSeconds(10);executorService.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executorService.setThreadFactory(new DefineThreadFactory("小王"));executorService.initialize();return executorService;}}import io.netty.util.concurrent.DefaultThreadFactory;/*** 这里图简单 ,继承了一个ThreadFactory实现*/
public class DefineThreadFactory extends DefaultThreadFactory {public DefineThreadFactory(String poolName) {super(poolName);}@Overridepublic Thread newThread(Runnable r) {Thread t = super.newThread(r);//给生成的线程设置一个错误处理器t.setUncaughtExceptionHandler(new ExceptionHandler());return t;}
}public class ExceptionHandler implements Thread.UncaughtExceptionHandler {@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println("define==Exception: " + e.getMessage());}
}
输出:
09:55:09.844 [main] INFO org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Initializing ExecutorService
【thread-name:小王-1-1,执行方式:execute方法】
define==Exception: 【thread-name:小王-1-1,执行方式:execute方法】,出现异常
可以看到 线程池中工作线程 的错误也被捕捉到了
总结
UncaughtExceptionHandler API 提供了一个优雅的方式,让我们可以处理线程的异常错误。