当前位置:首页 > 科技  > 软件

"线程池中线程异常后:销毁还是复用?"

来源: 责编: 时间:2024-04-02 17:16:51 237观看
导读一、一个线程池中的线程异常了,那么线程池会怎么处理这个线程?需要说明,本文的线程池都是java.util.concurrent.ExecutorService线程池,本文将围绕验证,阅读源码俩方面来解析这个问题。二、代码验证2.1 验证execute提交线

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

需要说明,本文的线程池都是java.util.concurrent.ExecutorService线程池,本文将围绕验证,阅读源码俩方面来解析这个问题。aUw28资讯网——每日最新资讯28at.com

二、代码验证

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 执行结果如下:

aUw28资讯网——每日最新资讯28at.com

aUw28资讯网——每日最新资讯28at.com

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 执行结果如下:

aUw28资讯网——每日最新资讯28at.com

aUw28资讯网——每日最新资讯28at.com

2.2.3 结论:

submit 提交到线程池的方式,如果执行中抛出异常,并且没有catch,不会抛出异常,不会创建新的线程。aUw28资讯网——每日最新资讯28at.com

三、源码解析

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

aUw28资讯网——每日最新资讯28at.com

aUw28资讯网——每日最新资讯28at.com

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

aUw28资讯网——每日最新资讯28at.com

aUw28资讯网——每日最新资讯28at.com

3.3 java.util.concurrent.ThreadPoolExecutor#processWorkerExit

aUw28资讯网——每日最新资讯28at.com

aUw28资讯网——每日最新资讯28at.com

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

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

还记得,我们在3.1的时候,发现submit也是调用了execute方法,但是在调用之前,包装了一层 RunnableFuture,那一定是在RunnableFuture的实现 FutureTask中有特殊处理了,我们查看源码可以发现。aUw28资讯网——每日最新资讯28at.com

aUw28资讯网——每日最新资讯28at.com

aUw28资讯网——每日最新资讯28at.com

aUw28资讯网——每日最新资讯28at.com

aUw28资讯网——每日最新资讯28at.com

但是,我们通过java.util.concurrent.FutureTask#get(),就可以获取对应的异常信息。aUw28资讯网——每日最新资讯28at.com

四、总结

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

◦当执行方式是execute时,可以看到堆栈异常的输出,线程池会把这个线程移除掉,并创建一个新的线程放到线程池中。aUw28资讯网——每日最新资讯28at.com

◦当执行方式是submit时,堆栈异常没有输出。但是调用Future.get()方法时,可以捕获到异常,不会把这个线程移除掉,也不会创建新的线程放入到线程池中。aUw28资讯网——每日最新资讯28at.com

以上俩种执行方式,都不会影响线程池里面其他线程的正常执行。aUw28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-80828-0.html&quot;线程池中线程异常后:销毁还是复用?&quot;

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 探索Golang的优雅爬虫框架 Colly

下一篇: .NET WebAPI 自定义返回类:实现统一与灵活的API响应

标签:
  • 热门焦点
  • K60至尊版狂暴引擎2.0加持:超177万跑分斩获性能第一

    Redmi的后性能时代战略发布会今天下午如期举办,在本次发布会上,Redmi公布了多项关于和联发科的深度合作,以及新机K60 Ultra在软件和硬件方面的特性,例如:“K60 至尊版,双芯旗舰
  • 服务存储设计模式:Cache-Aside模式

    Cache-Aside模式一种常用的缓存方式,通常是把数据从主存储加载到KV缓存中,加速后续的访问。在存在重复度的场景,Cache-Aside可以提升服务性能,降低底层存储的压力,缺点是缓存和底
  • 谷歌KDD'23工作:如何提升推荐系统Ranking模型训练稳定性

    谷歌在KDD 2023发表了一篇工作,探索了推荐系统ranking模型的训练稳定性问题,分析了造成训练稳定性存在问题的潜在原因,以及现有的一些提升模型稳定性方法的不足,并提出了一种新
  • 三分钟白话RocketMQ系列—— 如何发送消息

    我们知道RocketMQ主要分为消息 生产、存储(消息堆积)、消费 三大块领域。那接下来,我们白话一下,RocketMQ是如何发送消息的,揭秘消息生产全过程。注意,如果白话中不小心提到相关代
  • 为什么你不应该使用Div作为可点击元素

    按钮是为任何网络应用程序提供交互性的最常见方式。但我们经常倾向于使用其他HTML元素,如 div span 等作为 clickable 元素。但通过这样做,我们错过了许多内置浏览器的功能。
  • 本地生活这块肥肉,拼多多也想吃一口

    出品/壹览商业 作者/李彦编辑/木鱼拼多多也看上本地生活这块蛋糕了。近期,拼多多在App首页&ldquo;充值中心&rdquo;入口上线了本机生活界面。壹览商业发现,该界面目前主要
  • 东方甄选单飞:有些鸟注定是关不住的

    文/彭宽鸿编辑/罗卿东方甄选创始人俞敏洪带队的&ldquo;7天甘肃行&rdquo;直播活动已在近日顺利收官。成立后一年多时间里,东方甄选要脱离抖音自立门户的传闻不绝于耳,&ldquo;7
  • 苹果140W USB-C充电器:采用氮化镓技术

    据10 月 30 日 9to5 Mac 消息报道,当苹果推出新的 MacBook Pro 2021 时,该公司还推出了新的 140W USB-C 充电器,附赠在 MacBook Pro 16 英寸机型的盒子里,也支
  • AI艺术欣赏体验会在上海梅赛德斯奔驰中心音乐俱乐部上演

    光影交错的镜像世界,虚实幻化的视觉奇观,虚拟偶像与真人共同主持,这些场景都出现在2019世界人工智能大会的舞台上。8月29日至31日,“AI艺术欣赏体验会”在上海
Top