扩展线程池捕获线程异常

如何捕获线程池中的线程异常

简单案例

我们先看一个案例,实现Runnable接口,计算两个数的商
扩展线程池捕获线程异常_第1张图片
创建一个线程池,参数如下
扩展线程池捕获线程异常_第2张图片
提交任务到线程池,查看执行结果
扩展线程池捕获线程异常_第3张图片
执行结果
扩展线程池捕获线程异常_第4张图片

  • 我们发现,我们代码中,提交了5个线程,但最终只打印了4个结果,
  • 而且没有报何错误,很明显100/0的那个任务没有打印
  • 100/0会报除零异常,但是显然这次没有报任何错误

改用execute()提交线程

为了获得线程报错信息,我们可以改用execute()提交线程
扩展线程池捕获线程异常_第5张图片

  • 从这里的控制台,我们得到了部分的报错信息,但是我们只能知道异常是在哪里抛出来的,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;
                }
            }
        };
    }
}

我们用扩展后的线程池提交任务,还是刚才的代码
扩展线程池捕获线程异常_第6张图片
这样,我们就得到了异常发生的内部堆栈信息,帮助我们快速定位问题

你可能感兴趣的:(多线程,java,线程池,多线程,线程异常,并发编程)