【异常】捕获线程池执行任务时产生的异常

前言:

        在编写程序时,我们为了充分利用多核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>() {
            @Override
            public 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() {
            @Override
            public 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()方法,如下图所示。

        如果本文对你有所帮助,不妨点个赞支持一下!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值