前言:
在编写程序时,我们为了充分利用多核CPU、加快接口响应速度,通常会使用线程池来处理请求,但线程池执行任务过程中难免会出现异常,导致请求失败。那如果我们想在任务发生异常后捕获异常,并做一些”善后“操作,该如何做呢?
捕获方案:
1、try、catch:
public class ExceptionHandle {public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(1,2,30,TimeUnit.SECONDS,new LinkedBlockingQueue<>());executor.execute(() -> {try {//模拟业务代码出现异常int i = 1 / 0;}catch (Exception e){System.err.println(e.getMessage());}});executor.shutdown();}
}
原理:在编码时提前预知业务代码可能会发生异常,并用try块捕获业务异常,并在catch块做善后工作。
2、FutureTask:
public class ExceptionHandle {public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(1,2,30,TimeUnit.SECONDS,new LinkedBlockingQueue<>());Callable<Integer> callable = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {//模拟业务代码出现异常return 1/0;}};FutureTask<Integer> task = new FutureTask<Integer>(callable);executor.submit(task);try {task.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {//这里捕获的是真正的业务异常System.err.println(e.getCause().getMessage());}executor.shutdown();}
}
原理:FutureTask技能作为任务提交给线程执行,也能像Future一样通过get()方法获取任务执行结果。如果任务正常执行,那么返回的就是结果对象,如果执行出现异常,返回的就是异常对象;当发生异常时,try块就能捕获异常,并在catch块做相应处理。get()方法实现如下
//可能会抛出InterruptedException、ExecutionException
public V get() throws InterruptedException, ExecutionException {int s = state;if (s <= COMPLETING)s = awaitDone(false, 0L);return report(s);}
InterruptedException是线程在等待执行结果时,被其它线程打断所产生的异常。
用Future接口获取submit()方法的返回结果也能达到同样的效果,对FutureTask不太了解的话,可以看我的这篇博客:【Java】浅析FutureTask的核心方法get-CSDN博客
3、ThreadFactor:
public class ExceptionHandle {public static void main(String[] args) {//线程工厂用于给线程池创建的线程加上一些特征//你可以通过线程工厂指定线程的优先级、是否是守护线程等等ThreadFactory factory = new ThreadFactory() {@Overridepublic Thread newThread(Runnable r) {Thread t = new Thread(r);//t.setUncaughtExceptionHandler((Thread thread,Throwable e) -> {if(e != null){System.err.println(e.getMessage());}});return t;}};ThreadPoolExecutor executor = new ThreadPoolExecutor(1,2,30,TimeUnit.SECONDS,new LinkedBlockingQueue<>(),factory);executor.execute(() -> {//模拟业务异常int i = 1/0;});executor.shutdown();}
}
原理:
(1)ThreadFactor接口用于声明线程的属性,如线程的优先级、名称、守护进程状态等,它是线程池的构造参数之一;如果创建线程池时传入了ThreadFactor,线程池在创建线程时会按照ThreadFactor指定的形式来创建。
(2)我们让线程调用了setUncaughtExceptionHandler()方法,这个方法需要一个参数:UncaughtExceptionHandler接口,当线程由于未捕获的异常而突然终止时,会调用这个接口的uncaughtException()方法,我们可以自定义这个方法的实现逻辑,对异常做处理。相当于线程执行任务过程中如果出现异常,那么就会回调uncaughtException()方法,如下图所示。
如果本文对你有所帮助,不妨点个赞支持一下!