如何实现线程池中异常捕获
创作时间:
作者:
@小白创作中心
如何实现线程池中异常捕获
引用
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本身就是一个线程工厂,因此可以直接将其作为参数传递给自定义线程工厂。
通过这种方式,我们可以确保线程池中的所有线程都能正确处理未捕获的异常,并将异常信息记录到日志中。
热门推荐
岭南木色海洋板:通过严苛实实测,专为广东气候设计
米时|简单美味的糯米团子!福州传统美食
零失败草莓果酱DIY教程:自制草莓果酱备料和食谱大公开
桂花蜜的制作方法
干桂花怎么做桂花蜜 桂花蜜的功效与作用
干桂花制作桂花蜜的方法及功效
这届年轻人为何不爱走亲戚
为什么现在的亲戚越来越不亲了,这些原因,让大家越走越疏远
年轻一代亲戚关系疏远,家族规模或减小
土豆红烧肉:家常美味的制作秘诀
5次登春晚到“销声匿迹”,“小品女王”金玉婷,如今过得怎么样
从5登春晚沦落到精神病院,金玉婷的悲惨人生,印证了郭德纲的话
土豆焖红烧肉:美味与健康的完美融合
文山三七:健康管理的得力助手
云冰山:南方最美冰雪世界摄影攻略
永州的自然瑰宝:云冰山、阳明山、九嶷山
九嶷山:永州的5A级打卡圣地
跟着《东北插班生宝岛季》打卡台湾美景
《东北插班生》宝岛季开机在即,探秘拍摄地
悟空浏览器如何保存网盘资源
公认“不咬人”的狗狗有娃家庭也能养——拉布拉多猎犬
比格犬:国际公认的标准医学实验用犬
实验动物采血技术的精确应用
比格犬:有趣的灵魂加上可爱的外表
比格犬的喂食要点
比格犬:国际公认的标准医学实验用犬
民航局推出临时乘机证明,三种渠道60秒快速办理
赵本山新剧春节上线,陪你过新年
赵本山经典小品:从《卖拐》到《不差钱》的艺术传奇
赵本山双剧齐发引爆春节档,全球巡演蓄势待发