扩展线程池捕获线程异常
如何捕获线程池中的线程异常
简单案例
我们先看一个案例,实现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; } } }; } }
我们用扩展后的线程池提交任务,还是刚才的代码 这样,我们就得到了异常发生的内部堆栈信息,帮助我们快速定位问题