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

云上有数芯2024-03-28 10:21:01  146

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

需要说明,本文的线程池都是java.util.concurrent.ExecutorService线程池,本文将围绕验证,阅读源码俩方面来解析这个问题。

二、代码验证

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.1 java.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方法时,可以捕获到异常,不会把这个线程移除掉,也不会创建新的线程放入到线程池中。

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

转载此文是出于传递更多信息目的。若来源标注错误或侵犯了您的合法权益,请与本站联系,我们将及时更正、删除、谢谢。
https://www.414w.com/read/64455.html
0
随机主题
真要走了? 贾勒特-阿伦已取关骑士官方INS 此前传出交易流言辽篮夺冠谁是最大功臣?弗格无缘前四,第一名你应该想不到!阵容强大却口碑皆输的10大烂片, 全看过的我是服了看不到武磊vs孙兴慜? 媒体人: 孙兴慜恐无法参加与中国队的比赛终结G1五连败! 独行侠自2021年以来首次赢下系列赛G1刘亦菲: 美得跟画一样打起来了? 以军再次发起“斩首行动”, 以色列或被围攻, 美英失声别人只是说,咱们亲自拆开看!汽车内外循环原理,看完你就都明白啦助力乡村共同富裕! 第十六届浙江一市·宁海白枇杷文化活动举行乌苏为10家拥军企业授牌1957年毛主席去看望儿子,闲聊间毛岸青想到一事:爸爸你说怪不怪50多万的奥迪SUV降价超22万元, 车长4米9马力313匹值不值假吃演员们! 求求你们学学《庆余年2》付辛博是怎么演干饭戏的吧《庆余年2》林相搭上自己性命, 暗自助范闲精忠岳飞63:赵构连下十二道金牌,岳飞无奈班师回朝,朱仙镇的百姓嚎啕大哭……记者: 皇马今夏不会寻找克罗斯替代者, 但明年会买周琦家庭内景曝光! 客厅挺大 还有架子鼓 很快把娃带哭“山鸡”真成“凤凰”? 梅根的尼日利亚之行尽显英国“老钱”风BG推文《拉上始皇去造反》女帝文,超有野心一门心思造反的女主没想到她居然造的自己亲爹的反,收服的大才是自己的亲爹求新、求变的《梦幻西游》追求的是有血有肉的角色!低空经济利好不断! 炒作风暴有望继续爆发! 相关概念和潜力股曝光!
最新回复(0)