如何实现线程池中异常捕获
创作时间:
作者:
@小白创作中心
如何实现线程池中异常捕获
引用
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
方法。在这个方法中,系统会获取一个默认的异常处理器,这个处理器会将异常信息输出到控制台,而不是记录到日志中。
解决方案
要将控制台输出转换为日志输出,我们可以给线程添加一个自定义的异常处理器。具体步骤如下:
- 定义一个异常处理器:
@Slf4j
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
log.error("Exception Thread", e);
}
}
- 在创建线程时设置异常处理器:
Thread thread = new Thread(() -> {
if (1 == 1) {
log.error("error");
throw new RuntimeException("异常了");
}
});
// 设置异常处理器
thread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
thread.start();
这样即使没有显式捕获异常,抛出的异常也会被记录在日志中。
线程池如何进行异常处理?
在使用线程池时,可以通过自定义ThreadFactory
来实现异常处理。具体步骤如下:
- 自定义线程工厂:
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;
}
}
- 在线程池配置中使用自定义线程工厂:
@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
本身就是一个线程工厂,因此可以直接将其作为参数传递给自定义线程工厂。
通过这种方式,我们可以确保线程池中的所有线程都能正确处理未捕获的异常,并将异常信息记录到日志中。
热门推荐
医疗纠纷频发,尸检为何成关键证据?
北京协和医学院揭秘:医患纠纷背后的社会背景
医患纠纷背后的心理真相:从焦虑到信任的重建之路
夫妻长期争吵后如何合法离婚?
《爱情公寓》教你如何处理夫妻矛盾
当社交媒体遇上婚姻:如何避免虚拟世界里的感情危机?
中医助你摆脱噩梦困扰!
认知行为疗法:科学应对噩梦的有效方法
王晓霆:摆脱噩梦困扰,重获优质睡眠
同是物业状告业主,判决结果却大相径庭!律师这样说
流清水鼻涕是什么感冒
过敏性鼻炎鼻子流水怎么办
花粉季如何应对儿童过敏性鼻炎?
看病挂号难?这份实用就医指南请收好
《蛟龙行动》春节档上映,3800万电影消费券助力观影
CBA常规赛前30轮结束,季后赛12支球队出炉,几乎没有悬念
CBA:浙江广厦主场不敌上海 韦瑟斯庞首秀砍下11分
CBA最新积分榜:上海男篮虽列第12,但冲击四强优势明显
外援政策引发“鲶鱼效应”!CBA常规赛过半,群雄并立成主旋律
CBA最新排名:广厦双杀北京独一档 山西紧随其后 广东战绩狂飙
十大最常用的炒菜调料有哪些 炒菜用什么调料味道好
牙疼抑郁双管齐下?教你一招搞定
秋冬牙疼怎么办?别再迷信吃梨了!
兰花意象:从古诗词到当代文化的传承
46岁殷桃的秋冬佛系穿搭:用基础款打造高级感
殷桃春晚彩排惊艳亮相:46岁如26岁,冻龄美貌背后的秘密
殷桃46岁仍似26岁:健康生活的6个秘诀
餐饮业食品安全管理:以烤鱼为例
魔芋料理大挑战:健康又美味!
冬季烤鱼首选:鲈鱼、鳜鱼还是鲑鱼?