线程池中线程抛了异常,该如何处理?

在实际开发中,我们常常会用到线程池,但任务一旦提交到线程池之后,如果发生异常之后,怎么处理? 怎么获取到异常信息?在了解这个问题之前,可以先看一下 线程池的源码解析,从源码中我们知道了线程池的提交方式:submit和execute的区别,接下来分别使用他们执行带有异常的任务!看结果是怎么样的!
我们先用伪代码模拟一下线程池抛异常的场景:
 public class ThreadPoolException {public static void main(String[] args) {//创建一个线程池ExecutorService executorService= Executors.newFixedThreadPool(1);//当线程池抛出异常后 submit无提示,其他线程继续执行executorService.submit(new task());//当线程池抛出异常后 execute抛出异常,其他线程继续执行新任务executorService.execute(new task());}}//任务类class task implementsRunnable{@Overridepublic void run() {System.out.println("进入了task方法!!!");int i=1/0;}}运行结果:
 

线程池中线程抛了异常,该如何处理?

文章插图
 
可以看到:submit不打印异常信息,而execute则会打印异常信息!,submit的方式不打印异常信息,显然在生产中,是不可行的,因为我们无法保证线程中的任务永不异常,而如果使用submit的方式出现了异常,直接如上写法,我们将无法获取到异常信息,做出对应的判断和处理,所以下一步需要知道如何获取线程池抛出的异常!
推荐JAVA工程师技术指南:https://github.com/chenjiabing666/JavaFamily
submit()?想要获取异常信息就必须使用get()方法!!
 //当线程池抛出异常后 submit无提示,其他线程继续执行Future<?> submit = executorService.submit(new task());submit.get();submit打印异常信息如下:
 
线程池中线程抛了异常,该如何处理?

文章插图
 
方案一:使用 try -catch public class ThreadPoolException {public static void main(String[] args) {//创建一个线程池ExecutorService executorService = Executors.newFixedThreadPool(1);//当线程池抛出异常后 submit无提示,其他线程继续执行executorService.submit(new task());//当线程池抛出异常后 execute抛出异常,其他线程继续执行新任务executorService.execute(new task());}}// 任务类class task implements Runnable {@Overridepublic void run() {try {System.out.println("进入了task方法!!!");int i = 1 / 0;} catch (Exception e) {System.out.println("使用了try -catch 捕获异常" + e);}}}打印结果:
 
线程池中线程抛了异常,该如何处理?

文章插图
 
可以看到 submit 和 execute都清晰易懂的捕获到了异常,可以知道我们的任务出现了问题,而不是消失的无影无踪 。关注公众号:码猿技术专栏,回复关键词:1111 获取阿里内部Java性能调优手册!
方案二:使用Thread.setDefaultUncaughtExceptionHandler?方法捕获异常方案一中,每一个任务都要加一个try-catch? 实在是太麻烦了,而且代码也不好看,那么这样想的话,可以用Thread.setDefaultUncaughtExceptionHandler方法捕获异常
 
线程池中线程抛了异常,该如何处理?

文章插图
 
UncaughtExceptionHandler 是Thread类一个内部类,也是一个函数式接口 。
推荐Java工程师技术指南:https://github.com/chenjiabing666/JavaFamily
内部的uncaughtException是一个处理线程内发生的异常的方法,参数为线程对象t和异常对象e 。
 
线程池中线程抛了异常,该如何处理?

文章插图
 
应用在线程池中如下所示:重写它的线程工厂方法,在线程工厂创建线程的时候,都赋予UncaughtExceptionHandler处理器对象 。
 public class ThreadPoolException {public static void main(String[] args) throws InterruptedException {//1.实现一个自己的线程池工厂ThreadFactory factory = (Runnable r) -> {//创建一个线程Thread t = new Thread(r);//给创建的线程设置UncaughtExceptionHandler对象 里面实现异常的默认逻辑t.setDefaultUncaughtExceptionHandler((Thread thread1, Throwable e) -> {System.out.println("线程工厂设置的exceptionHandler" + e.getMessage());});return t;};//2.创建一个自己定义的线程池,使用自己定义的线程工厂ExecutorService executorService = new ThreadPoolExecutor(1,1,0,TimeUnit.MILLISECONDS,new LinkedBlockingQueue(10),factory);// submit无提示executorService.submit(new task());Thread.sleep(1000);System.out.println("==================为检验打印结果,1秒后执行execute方法");// execute 方法被线程工厂factory 的UncaughtExceptionHandler捕捉到异常executorService.execute(new task());}}class task implements Runnable {@Overridepublic void run() {System.out.println("进入了task方法!!!");int i = 1 / 0;}}


推荐阅读