当前位置: 首页 > article >正文

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

前言:

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

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


http://www.kler.cn/a/155843.html

相关文章:

  • Linux kernel 堆溢出利用方法(二)
  • 【juc】AbstractQueuedSynchronized为什么采用双向链表
  • node.js安装和配置教程
  • CSS 自定义滚动条样式
  • Java Stream 流常用操作大全
  • OLED 显示画面的变换操作——上下、左右翻转
  • Hdoop学习笔记(HDP)-Part.03 资源规划
  • 微服务详细介绍(什么是微服务)
  • go并发编程(中)
  • 【计网 面向连接的传输TCP】 中科大笔记 (十 二)
  • 每日一题:LeetCode-209. 长度最小的子数组(滑动窗口)
  • JAVA代码优化:Spring中redis的工具类
  • 计算机视觉(CV)技术的优势和挑战-AI生成版
  • HarmonyOS应用开发者高级认证--96分
  • Nested Named Entity Recognition with Span-level Graphs
  • Linux脚本awk命令
  • SpringBootCache缓存——j2cache
  • docker容器内部文件挂载主机
  • 查看MySQL中具体哪个部分占用了内存
  • 【Python/Java/C++三种语言】20天拿下华为OD笔试之【哈希表】2023B-单词接龙【欧弟算法】全网注释最详细分类最全的华为OD真题题解
  • 纯cpp如何模拟qt的信号与槽
  • 计算UDP报文CRC校验的总结
  • vue2+element-ui npm run build打包后,在服务器打开报错
  • vue 使用decimal.js 解决小数相加合计精确度丢失问题
  • 强化学习------时序差分(Temporal-Difference Learning)
  • 【开源】基于Vue.js的超市账单管理系统的设计和实现