如何捕获线程池中的线程异常
简单案例
我们先看一个案例,实现Runnable接口,计算两个数的商
创建一个线程池,参数如下
提交任务到线程池,查看执行结果
执行结果
- 我们发现,我们代码中,提交了5个线程,但最终只打印了4个结果,
- 而且没有报何错误,很明显100/0的那个任务没有打印
- 100/0会报除零异常,但是显然这次没有报任何错误
改用execute()提交线程
为了获得线程报错信息,我们可以改用execute()提交线程
- 从这里的控制台,我们得到了部分的报错信息,但是我们只能知道异常是在哪里抛出来的,ThreadPoolTest.java的第51行;
- 但是我们还是希望得到其他的更重要的信息,这个任务在哪里提交的?
扩展线程池ThreadPoolExecutor
我们可以扩展一下ThreadPoolExecutor这个线程池,让他在任务调度前,先保存一下提交任务线程的堆栈信息
package com.stream.juc;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 扩展线程池
* 捕获线程池的异常
*
* @author stream
* @since 2021/9/15 7:51
*/
class ExtenThreadPoolExecutor extends ThreadPoolExecutor {
public ExtenThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, CallerRunsPolicy callerRunsPolicy) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
public void execute(Runnable command) {
super.execute(wrap(command,clientTrace(),Thread.currentThread().getName()));
}
@Override
public Future<?> submit(Runnable task) {
return super.submit(wrap(task,clientTrace(),Thread.currentThread().getName()));
}
// 抛出异常信息
private Exception clientTrace(){
return new Exception("Thread Stack");
}
private Runnable wrap(Runnable task, Exception exception , String name) {
return new Runnable() {
@Override
public void run() {
try {
task.run(); // 捕获异常
}catch (Exception e){
exception.printStackTrace();
throw e;
}
}
};
}
}
我们用扩展后的线程池提交任务,还是刚才的代码
这样,我们就得到了异常发生的内部堆栈信息,帮助我们快速定位问题