线程池异常处理

发布时间 2023-08-25 14:37:52作者: 川流不息&

背景:有时候我们把一些业务逻辑丢在线程池处理,本身的业务方法又没有打印日志,导致这个方法执行过程中是否出错了根本不知道,异常信息基本丢失,问题不好排除。

方式一 简单粗暴 try catch 执行的方法
 @Test
    public void testThreadException(){
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,5,2,
                TimeUnit.SECONDS,new LinkedBlockingDeque<>(20)
                ,new ThreadPoolExecutor.CallerRunsPolicy());

        for (int i = 0;i < 5;i++){
            int finalI = i;
            threadPoolExecutor.execute(()-> log.info("{}",test(finalI)));
        }
        threadPoolExecutor.shutdown();
    }

    public int test(int i){
        try {
            return 2/i;
        }catch (Exception e){
            log.error("线程{}出错了",Thread.currentThread().getName(),e);
            return i;
        }
    }
}
方式二 重写一下 线程工厂中给线程设置uncaughtExceptionHandler
@Test
    public void testThreadException(){
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,5,2,
                TimeUnit.SECONDS,new LinkedBlockingDeque<>(20),
                threadFactory -> {
                    Thread t = new Thread(threadFactory);
                    // 获取线程池中的异常
                    t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                        @Override
                        public void uncaughtException(Thread t, Throwable e) {
                            // 对异常进行处理
                            log.error("线程{}出错了",t.getName(),e);
                        }
                    });
                    return t;
                }
                ,new ThreadPoolExecutor.CallerRunsPolicy());

        for (int i = 0;i < 5;i++){
            int finalI = i;
            threadPoolExecutor.execute(()-> log.info("{}",test(finalI)));
        }
        threadPoolExecutor.shutdown();
    }

    public int test(int i){
        return 2/i;
    }

总结:方式二 更加好,可以统一定义好,这样项目里面都用公用的线程池, 可以防止有些方法 异常日志丢失了 造成排错困难。