线程池中线程异常后到底是怎么处理的

一、一个线程池中的线程异常了,那么线程池会怎么处理这个线程?

二、代码验证

2.1 验证execute提交线程池中

2.1.1 测试代码:

复制代码
public class ThreadPoolExecutorDeadTest {
    public static void main(String[] args) throws InterruptedException {        ExecutorService executorService = buildThreadPoolExecutor();        executorService.execute(() -> exeTask("execute"));        executorService.execute(() -> exeTask("execute"));        executorService.execute(() -> exeTask("execute-exception"));        executorService.execute(() -> exeTask("execute"));        executorService.execute(() -> exeTask("execute"));

        Thread.sleep(5000);        System.out.println("再次执行任务=======================");
        executorService.execute(() -> exeTask("execute"));        executorService.execute(() -> exeTask("execute"));        executorService.execute(() -> exeTask("execute"));        executorService.execute(() -> exeTask("execute"));        executorService.execute(() -> exeTask("execute"));    }

    public static ExecutorService buildThreadPoolExecutor() {        return new ThreadPoolExecutor(5, 10, 30, TimeUnit.SECONDS,                new LinkedBlockingQueue<>(1000), new ThreadFactoryBuilder().setNameFormat("test-%s").build()                , new ThreadPoolExecutor.CallerRunsPolicy());    }
    private static void exeTask(String name) {        String printStr = "[thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name + "]";        if ("execute-exception".equals(name)) {            throw new RuntimeException(printStr + ", 我抛异常了");        } else {            System.out.println(printStr);        }    }}

2.1.2 执行结果如下:

2.1.3 结论:

execute 提交到线程池的方式,如果执行中抛出异常,并且没有在执行逻辑中catch,那么会抛出异常,并且移除抛出异常的线程,创建新的线程放入到线程池中。

2.2 验证submit提交线程池中

2.2.1 测试代码:

复制代码
public class ThreadPoolExecutorDeadTest {
    public static void main(String[] args) throws InterruptedException {        ExecutorService executorService = buildThreadPoolExecutor();        executorService.submit(() -> exeTask("execute"));        executorService.submit(() -> exeTask("execute"));        executorService.submit(() -> exeTask("execute-exception"));        executorService.submit(() -> exeTask("execute"));        executorService.submit(() -> exeTask("execute"));

        Thread.sleep(5000);        System.out.println("再次执行任务=======================");
        executorService.submit(() -> exeTask("execute"));        executorService.submit(() -> exeTask("execute"));        executorService.submit(() -> exeTask("execute"));        executorService.submit(() -> exeTask("execute"));        executorService.submit(() -> exeTask("execute"));    }

    public static ExecutorService buildThreadPoolExecutor() {        return new ThreadPoolExecutor(5, 10, 30, TimeUnit.SECONDS,                new LinkedBlockingQueue<>(1000), new ThreadFactoryBuilder().setNameFormat("test-%s").build()                , new ThreadPoolExecutor.CallerRunsPolicy());    }
    private static void exeTask(String name) {        String printStr = "[thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name + "]";        if ("execute-exception".equals(name)) {            throw new RuntimeException(printStr + ", 我抛异常了");        } else {            System.out.println(printStr);        }    }}

2.2.2 执行结果如下:

2.2.3 结论:

submit 提交到线程池的方式,如果执行中抛出异常,并且没有catch,不会抛出异常,不会创建新的线程。

三、源码解析

3.1java.util.concurrent.AbstractExecutorService#submit(java.lang.Runnable)

3.2查看execute方法的执行逻辑java.util.concurrent.ThreadPoolExecutor#runWorker

3.3 java.util.concurrent.ThreadPoolExecutor#processWorkerExit

可以发现,如果抛出异常,会移除抛出异常的线程,创建新的线程。

3.4 为什么submit方法,没有创建新的线程,而是继续复用原线程?

还记得,我们在3.1的时候,发现submit也是调用了execute方法,但是在调用之前,包装了一层 RunnableFuture,那一定是在RunnableFuture的实现 FutureTask中有特殊处理了,我们查看源码可以发现。

但是,我们通过java.util.concurrent.FutureTask#get(),就可以获取对应的异常信息。

四、总结

当一个线程池里面的线程异常后:

  • 当执行方式是execute时,可以看到堆栈异常的输出,线程池会把这个线程移除掉,并创建一个新的线程放到线程池中。

  • 当执行方式是submit时,堆栈异常没有输出。但是调用Future.get()方法时,可以捕获到异常,不会把这个线程移除掉,也不会创建新的线程放入到线程池中。其实submit不需要看源码也能理解,肯定不会影响,因为是线程池已经执行完了,Future.get的时候才会有异常。

以上俩种执行方式,都不会影响线程池里面其他线程的正常执行。

相关推荐
2301_81016095几秒前
C++与Docker集成开发
开发语言·c++·算法
jgbazsh几秒前
Spring中把一个bean对象交给Spring容器管理的三种方式
java·后端·spring
CSDN_Colinw2 分钟前
C++模块化设计原则
开发语言·c++·算法
Network porter3 分钟前
IDEA2025(2025.2)都更新了什么???
java·intellij-idea·idea
MicroTech20254 分钟前
微算法科技(NASDAQ: MLGO)使用机器学习保障量子安全下区块链高效可用
科技·算法·机器学习
m0_662577974 分钟前
C++中的模板方法模式
开发语言·c++·算法
twc8295 分钟前
不可言说的知识:AI时代软件工程的核心传递问题
java·人工智能·大模型·软件工程·知识工程
We་ct6 分钟前
LeetCode 33. 搜索旋转排序数组:O(log n)二分查找
前端·算法·leetcode·typescript·个人开发·二分·数组
孤影过客7 分钟前
Flutter高性能任务管理APP开发实战代码解析
jvm·flutter·oracle
智驱力人工智能8 分钟前
一盔一带AI抓拍系统能否破解非机动车执法取证难 骑行未戴头盔检测 电动车未戴头盔智能监测 摩托车头盔佩戴AI识别系统 边缘计算实时处理
人工智能·算法·yolo·目标检测·边缘计算