问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

如何实现线程池中异常捕获

创作时间:
作者:
@小白创作中心

如何实现线程池中异常捕获

引用
CSDN
1.
https://m.blog.csdn.net/2401_89221445/article/details/145856231

在多线程编程中,异常处理是一个容易被忽视但又非常重要的环节。本文将详细介绍如何在Java线程池中实现异常捕获,确保异常信息能够被正确记录和处理。

线程出现异常

在多线程环境中,如果线程执行任务时没有添加异常处理,一旦任务内部发生异常,错误信息将无法被记录下来。例如:

Thread thread = new Thread(() -> {
    if (1 == 1) {
        log.error("error");
        throw new RuntimeException("异常了");
    }
});
thread.start();

可以看到,异常不会打印日志,而是输出在控制台上了。那么异常去了哪里?

异常去了哪里?

正常来说,如果我们进行了异常捕获,是可以看到日志信息的:

Thread thread = new Thread(() -> {
    try {
        log.info("hello");
        throw new RuntimeException("运行时异常了");
    } catch (Exception e) {
        log.error("异常发生", e);
    }
});
thread.start();

但是如果是一个未捕获的异常,异常是抛到控制台上的,什么原因呢?

如果一个异常未被捕获,从线程中抛了出来。JVM会回调Thread类中的dispatchUncaughtException方法。在这个方法中,系统会获取一个默认的异常处理器,这个处理器会将异常信息输出到控制台,而不是记录到日志中。

解决方案

要将控制台输出转换为日志输出,我们可以给线程添加一个自定义的异常处理器。具体步骤如下:

  1. 定义一个异常处理器:
@Slf4j
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        log.error("Exception Thread", e);
    }
}
  1. 在创建线程时设置异常处理器:
Thread thread = new Thread(() -> {
    if (1 == 1) {
        log.error("error");
        throw new RuntimeException("异常了");
    }
});
// 设置异常处理器
thread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
thread.start();

这样即使没有显式捕获异常,抛出的异常也会被记录在日志中。

线程池如何进行异常处理?

在使用线程池时,可以通过自定义ThreadFactory来实现异常处理。具体步骤如下:

  1. 自定义线程工厂:
public class MyThreadFactory implements ThreadFactory {
    private static final MyUncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER = new MyUncaughtExceptionHandler();
    private ThreadFactory originalThreadFactory;

    public MyThreadFactory(ThreadFactory originalThreadFactory) {
        this.originalThreadFactory = originalThreadFactory;
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread thread = originalThreadFactory.newThread(r);
        // 设置我们自定义的异常处理器
        thread.setUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER);
        return thread;
    }
}
  1. 在线程池配置中使用自定义线程工厂:
@Configuration
public class ThreadPoolConfig {
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("MyExecutor-");
        executor.setThreadFactory(new MyThreadFactory(executor));
        executor.initialize();
        return executor;
    }
}

由于ThreadPoolTaskExecutor本身就是一个线程工厂,因此可以直接将其作为参数传递给自定义线程工厂。

通过这种方式,我们可以确保线程池中的所有线程都能正确处理未捕获的异常,并将异常信息记录到日志中。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号