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

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

二、代码验证

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的时候才会有异常。

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

相关推荐
qq_380619161 分钟前
SQL中如何实现特定范围内数据的批量删除_范围分区与分区删除
jvm·数据库·python
gelald3 分钟前
SpringBoot - Actuator与监控
java·spring boot·后端
深紫色的三北六号3 分钟前
仿大疆司空2面状航线生成——凸多边形区域航线生成算法详解
java·算法·无人机·大疆·航线规划
qq_3806191613 分钟前
HTML函数开发需要独立显卡吗_HTML函数与显卡关系详解【说明】
jvm·数据库·python
电商API&Tina27 分钟前
1688 拍立淘接口(item_search_img)测试与接入实战心得
java·大数据·前端·物联网·oracle·json
行走的搬运工33 分钟前
Spring Security_05
java·spring·mybatis
2201_7568473336 分钟前
Golang如何处理JSON空值null_Golang JSON空值处理教程【精通】
jvm·数据库·python
我登哥MVP36 分钟前
【Spring6笔记】 - 11 - JDBCTemplate
java·数据库·spring boot·mysql·spring
YuanDaima204844 分钟前
双指针基础原理与题目说明
数据结构·人工智能·python·算法·leetcode·手撕代码
hef2881 小时前
怎么诊断MongoDB Config Server响应极慢的问题_高频Auto-split导致的元库写入压力
jvm·数据库·python