如何实现线程池中异常捕获
创作时间:
作者:
@小白创作中心
如何实现线程池中异常捕获
引用
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本身就是一个线程工厂,因此可以直接将其作为参数传递给自定义线程工厂。
通过这种方式,我们可以确保线程池中的所有线程都能正确处理未捕获的异常,并将异常信息记录到日志中。
热门推荐
哪一种水草最增氧
哪一种水草最增氧
玉米价格受什么影响?这些影响怎样分析和了解?
南昌天香园游玩攻略 附游玩路线
上杉谦信的武力支柱——探析其手下的名将们
四川队三大国手合砍71分逆转北京队 豪取15连胜
皇帝的嫂子该怎么称呼?大明天子会不会有嫂子?他们之间关系如何
大众速腾缺点和优点有哪些?一汽大众速腾口碑怎么样
咳嗽可以吃芋头吗?医生的专业解答来了
大模型之提示词工程原理:提示学习(prompt learning)
20 个国家面临严重人道主义危机,塔利班:阿富汗目前已有改善
化工厂如何加强消防管理
廊坊市安次区:农业新技术助力农民增产增收
海马究竟属于哪个生物类目?
黄喉是什么(黄喉是牛的哪个部位)
证券开户的方式有哪些?不同开户方式的优缺点是什么?
开户是什么意思
红楼梦人物关系图解:从贾府五代到四大家族
为什么文件名里不能有英文冒号\:
解析心电图T波的正常变异:定义、类型与鉴别指南
13套小户型阳台储物柜造型设计,家里分分钟多出10平米,真心实用
50平小户型公寓设计,厨房阳台打通,打造宽敞明亮的开放式空间
一组槿花诗歌,木槿花开,绚烂多彩,夏日阴凉
木槿花的花语是什么?木槿花有哪些象征意义?
研发项目中如何实现有效的危机管理
缠论走势中枢的延伸、扩展、扩张
缠论第三类买点后,中枢的构成应该如何判断?
如何解读SGS阻燃测试报告
苦瓜:营养丰富的蔬菜佳品
实用与美观兼具的手机壳选购指南:从类型到清洁全面解析