线程池执行的用户任务抛出异常会怎样?

面试官:线程池执行的用户任务抛出异常会怎样? 源码分析看源码可以知道,中的任务都是在runWorker中执行的通过源码可以看到1149行执行用户任务1150~1155处理捕获任务异常,并抛出抛出异常后会退出,从任务队列中拉取任务的循环然后执行1167行,worker线程退出的逻辑看一下线程退出的逻辑如果是异常退出,参数为true如果状态值比STOP小,即线程池没有停止,会重新创建一个worker线程总结 如果用户任务抛出了异常,在线程池运行的状态下,会重新创建一个worker线程。这里就可能存在一个风险,即如果用户任务大量的抛出异常,可能会导出线程资源 阅读详情

点击上方“芋道源码”,选择“设为星标”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:blog.youkuaiyun.com/qq_26824159/

article/details/126767372


ThreadPoolExecutor.execute

源码分析

看源码可以知道,ThreadPoolExecutor中的任务都是在runWorker中执行的

329a29b5f172e023060e20e81841d9a1.png

通过源码可以看到

  • 1149行执行用户任务

  • 1150~1155处理捕获任务异常,并抛出

  • 抛出异常后会退出,从任务队列中拉取任务的循环

  • 然后执行1167行,worker线程退出的逻辑

看一下线程退出的逻辑

61f4c5693c37b2bd35e92fd097a1cd64.png
  • 如果是异常退出,参数completedAbruptly为true

  • 如果状态值比STOP小,即线程池没有停止,会重新创建一个worker线程

总结

ThreadPoolExecutor.execute 如果用户任务抛出了异常,在线程池运行的状态下,会重新创建一个worker线程。

这里就可能存在一个风险,即如果用户任务大量的抛出异常,可能会导出线程资源频繁的销毁、创建。

因此,需要用户任务应当主动对异常进行处理,而不是消极的抛给线程池。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

ThreadPoolExecutor.submit

源码分析

通过 ThreadPoolExecutor.submit 提交的用户任务,会包装成一个FutureTask,返回一个Future对象。因此异常处理的逻辑和ThreadPoolExecutor.execute有些差别

看一个FutureTask.run方法

40098db81f67d1fbfdd4354ee66373bd.png

从源码可以看到,FutureTask执行用户任务,如果异常,不会对外抛出,仅是记录

但是在调用Future.get时,会抛出异常,但此时的线程不是线程池的线程了,而是用户线程,因此对线程池是友好的。

总结

ThreadPoolExecutor.submit 提交的用户任务,会包装成一个FutureTask,FutureTask执行用户任务,如果异常,不会对外抛出,仅是记录,但是在调用Future.get时,会抛出异常。

异常是在用户线程中抛出的,因此不影响线程池中的线程。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

ScheduledThreadPoolExecutor.schedule

源码分析

ScheduledThreadPoolExecutor.schedule会将用户任务包装为ScheduledFutureTask,ScheduledFutureTask是FutureTask的子类,看下ScheduledFutureTask的执行逻辑

af75417d14f356ee7bee8813aaf48b39.png

ScheduledFutureTask是FutureTask的子类,所以有异常时,也不是抛出,而是记录

  • 293行对于非周期性任务,执行一次,如果有异常,不抛出,仅记录

  • 294~296对于周期性任务,执行完本次后,会设置下次执行的时间。如果本次出现异常,ScheduledFutureTask.super.runAndReset()返回结果为false(这个可以从源码看到),此时不会设置下次任务调度的时间了,因此会导致周期性任务失效的现象,并且异常信息不会抛出,也不会打印

总结

ScheduledThreadPoolExecutor.schedule提交的用户任务,如果出现异常,是不会抛出的,也不会打印。

对于非周期性任务和周期性任务,执行异常,都没有办法感知(不抛出、看不到)。

对于周期性任务,任何一次调度时,任务出现异常,都会导致后续无法调度。

因此,在使用这个线程池时,我们应当保证用户任务不会抛出异常到执行线程,避免任务调度失效,和异常排查困难等问题。

思考:ThreadPoolExecutor.execute发生异常时为什么要退出

ThreadPoolExecutor.execute出现用户任务异常时,为什么要退出当前线程,再重新创建一个线程呢?

我思考了半天,觉得原因之一可能是:

ThreadPoolExecutor的可以指定线程工厂,如果我的线程工厂是这样的

ThreadFactory threadFactory = new ThreadFactory() {
    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                // 处理异常的逻辑
            }
        });
        return thread;
    }
};

即在ThreadFactory创建线程时,指定了对未捕获的异常的处理器。

这种情况下,如果线程池不把发生异常的线程退出,可能会导致异常没有走到用户期望的逻辑上,因此需要将发生异常的线程退出,然后JVM调用UncaughtExceptionHandler。



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

075452f54716e7c1adacb4e05ce04e25.png

已在知识星球更新源码解析如下:

83f49f95cfa261fb4a47a496c7d2950a.jpeg

03488d737138779c8a639458f8bc8afa.jpeg

6f840c12186bcf2c4f0109433eb8cdf4.jpeg

6f2cb4ec765efcff20bc43f389406a2d.jpeg

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
在Java中通过线程池实现异步执行 1 什么是通过线程池实现代码的异步执行 1.1 什么是同步执行 与异步相对的是同步,这里先解释一下同步执行,同步执行就是平时执行我们的代码,由上至下顺序执行,中间如果有异常或错误出现不会继续往下执行。这也是绝大多数代码的执行方式。比如如下代码。 System.out.println("a"); Thread.sleep(2000); System.out.println("b"); System.out.println("c"); 这四... 阅读详情

相关推荐

SpringBoot 中异步任务实现及自定义线程池执行异步任务

java复制代码import org.springframework.context.annotation.Bean;// 核心线程数// 最大线程数// 任务队列大小// 线程池名称前缀// 允许线程的空闲时间/*** 拒绝处理策略* CallerRunsPolicy():交由调用方线程运行,比如 main 线程。* AbortPolicy():直接抛出异常。* DiscardPolicy():直接丢弃。

m0_73311735的博客 2495

线程池执行的用户任务抛出异常会怎样

线程池执行的用户任务抛出异常会怎样

lanicc's blog 1223

线程池+ FutureTask异步执行多任务

之前会员领取查询的接口超时了,因为有用户订购的会员有点多哈哈 解决方案: 用线程池+ FutureTask将1个查询拆分成多个小查询 由于FutureTask仅执行1次run()的特性(即使有多次调用也只执行1次),避免了重复查询的可能。而且多任务异步执行也能提高接口响应速度。 若对FutureTask仅执行1次run()有疑问,可看: FutureTask为何仅执行一次run()?. 一、线程池+FutureTask执行多任务计算 public class Test { //线程池最好作为全局变量

qq_44384533的博客 3049

面试官问:Java线程池执行的用户任务抛出异常会怎样?

ThreadPoolExecutor.execute源码分析看源码可以知道,ThreadPoolExecutor中的任务都是在runWorker中执行的图片通过源码可以看到1149行执行用户任务1150~1155处理捕获任务异常,并抛出抛出异常后会退出,从任务队列中拉取任务的循环然后执行1167行,worker线程退出的逻辑看一下线程退出的逻辑图片如果是异常退出,参数completedAbrupt...

Java精选 1120

面试题:线程池执行的用户任务抛出异常会怎样?

ThreadPoolExecutor.execute 如果用户任务抛出了异常,在线程池运行的状态下,会重新创建一个worker线程。这里就可能存在一个风险,即如果用户任务大量的抛出异常,可能会导出线程资源频繁的销毁、创建。因此,需要用户任务应当主动对异常进行处理,而不是消极的抛给线程池。

xuxu96 186

95-235-040-源码-task-Flink 对用户代码异常处理

1.视界 2.概述 ​ flink 的架构在 flink 基本组件一节已经介绍过,其中的 TaskManager 负责监护 task 的执行,对于每个 task,flink 都会启动一个线程去执行,那么当用户的代码抛出异常时,flink 的处理逻辑是什么呢? 3.异常后的组件通信 一个 flink task 的线程 Runnable 类是 Task.java,我们观察到它的 run() 方法整个被一个大的 try catch 包住,这里重点关注 catch 用户异常之后的部分: catch (Throwa

九师兄 678

线程池中的线程发生异常被UncaughtExceptionHandler捕获后为啥不能直接重启

先来讲讲我们生成一个任务提交给线程池,线程池是如何启动这个任务的。上图firstTask就是我们提交的任务,将firstTask作为属性传递给Worker实例化对象,Worker实例化的时候是这样的:Worker会获取该线程池中的线程工厂把当前Worker对象作为一个Runnable对象传给线程工厂@Override//自定义方法,非JDK源码 public Thread newThread(Ru...

qq_35689573的博客 3816

手把手教你用STM32实现SPWM逆变器控制(附完整代码)

本文提供了一份基于STM32实现SPWM逆变器控制的完整实战指南。文章从硬件选型(如STM32F103C8T6、IR2104驱动器)入手,详细解析了利用定时器TIM1生成SPWM波形的核心原理与代码实现,并涵盖了驱动电路、全桥功率电路及LC滤波器的设计要点与调试技巧,旨在帮助读者从零构建一个可靠的单相全桥逆变器系统。

weixin_29208327的博客 592

当线程池任务抛出异常

线程池原理剖析

王星星 2715

【详细图文】使用MobaXterm的SSH功能远程连接服务器,并创建pytorch环境,使用yolov8训练数据集

使用MobaXterm的SSH功能远程连接服务器,并创建pytorch环境,使用yolov8训练数据集,以及MobaXterm使用介绍和linux基础命令介绍。

qq_62844901的博客 3385

D类功放几种常见“爆破音”问题根源与改善措施

在数字D类功放刚上电或功放播放状态切换时,人耳偶尔会听到“嘣”的声音,我们把这个爆破的Pop Noise。数字功放Pop Noise 出现的原因有很多,本文主要分析Pop Noise 出现原因,并提供相应解决方法。

qq_26815321的博客 3593

线程池内运行的线程抛异常,线程池会怎么办

当线程池中线程执行任务的时候,任务出现未被捕获的异常的情况下,线程池会将允许该任务的线程从池中移除并销毁,且同时会创建一个新的线程加入到线程池中;可以通过ThreadFactory自定义线程并捕获线程内抛出的异常,也就是说甭管我们是否去捕获和处理线程池中工作线程抛出的异常,这个线程都会从线程池中被移除。

数据与算法架构提升之路专栏 6362

手把手教你用组态王KingSCADA 3.53读取S7-1200 PLC数据(保姆级图文教程)

本文提供了一份详细的组态王KingSCADA 3.53读取S7-1200 PLC数据的实战教程,涵盖从硬件连接到软件配置、变量映射到故障排查的全流程。特别针对初学者常见问题提供解决方案,帮助工程师快速实现稳定通信,提升工业自动化系统效率。

weixin_26876073的博客 678

线程池异常如何处理?

忽的一下,想到了线程池的比较重要的一个参数:ThreadFactory接口,这个接口的作用是按需创建新线程的,使用线程工厂消除了对Thread#Thread(Runnable) new Thread的强依赖,使应用程序能够使用特殊的Thread子类、优先级等。大白话就是让线程池中的线程使用我们自定义的线程,这个自定义可不是我们通过execute()或submit()传进来的自定义线程,而是Worker类中的thread变量,也就是实际运行的线程,我们看一下Worker类的构造方法。

lucky_love816的博客 2825

EWF写保护功能详解:从安装到实战操作指南

本文详细介绍了EWF写保护功能的安装与实战操作指南。EWF(Enhanced Write Filter)通过重定向写入操作保护硬盘分区,特别适合需要长期稳定运行的系统场景。文章涵盖从安装准备、图形界面操作到命令行高级管理的全流程,并提供了常见问题的解决方案,帮助用户轻松掌握这一实用工具。

weixin_28710999的博客 448

21天教你学会PCIe专栏(21)--总结和展望

回顾整个课程的主要内容和知识点总结PCIe技术的发展历程和现状展望PCIe技术的未来发展趋势和应用方向分享学习心得和实践经验1.1 课程回顾基础知识:了解了PCIe的基本概念、发展历程、标准和规范。分层结构:学习了PCIe的物理层、数据链路层和事务层的结构和功能。功能和特性:掌握了PCIe的热插拔、电源管理、多功能设备等高级功能。高速接口技术:学习了PCIe 4.0、5.0和未来趋势。实际案例分析:分析了GPU加速器和存储设备的PCIe设计和优化。常见问题和解决方案。

xiaoheshang_123的博客 673

JavaEE 初阶篇-深入了解线程池(线程池创建、线程池如何处理任务)

假设用户发起一个请求,后台就需要创建一个新线程来处理,下次新任务来了肯定又要创建新线程处理的,而创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,这样会严重影响系统的性能。该方法创建出来的线程池特点为,当任务越多时候,线程池中的线程数量也会随之增加。很惊奇的发现,核心线程竟然是 0 个,而临时线程数量的最大值是非常非常大的,如果线程任务执行完毕且空闲了 60 s则会被回收掉。将 Runnable 类型的任务交给线程池,线程池就会自动创建线程,自动执行 run() 方法且自动启动线程。

小扳手 2750

【车载以太网】Eth Stack Bringup

摘要:本文基于AUTOSAR架构,详细介绍了在TC3xx硬件平台上实现EthStack Bringup的全过程。作者通过配置MCAL和Davinci工具,完成了EthTrcv、Eth、EthIf、EthSM和TcpIp等模块的集成,并解决了16字节内存对齐和以太网速率不匹配等问题。最终实现了PC端与开发板的Ping通,并通过WireShark验证了数据包收发。文章总结了调试中的关键问题与解决方案,强调了实践的重要性,为后续EthStack的深入分析奠定了基础。

qq_36056498的博客 183

线程池中几个重要的参数及线程池中中任务的执行流程

5个核心线程(在池中一直保持)。最多增加15个线程,总线程数达到20个(即最大线程数)。100个任务被丢弃或拒绝,具体取决于配置的拒绝策略。

m0_71983809的博客 1973

《手把手教你修复过期K8s集群证书:记一次K8s集群起死回生实录》

今天本想打开半年前部署的K8s测试集群跑个Demo,结果`kubectl`直接报错`certificate has expired`!作为一名云原生老司机,我决定把这次'抢救'过程记录下来,手把手带大家解决这个运维常见问题。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 3780

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

探秘提交任务到线程池后源码的执行流程

7]如果说线程池状态确实是RUNNING,也就是二次校验通过,那么就判断一下线程池里是否还有线程,通过WorkerCountOf(recheck) == 0来判断,如果返回true了,就说明当前线程池中是空的,没有线程。对于核心线程来说,他们可以无限制的等待着任务被获取并执行,而非核心的线程则是在有限的时间内获取任务,一旦Worker无法获取到任务,也就是要获取的任务为空,循环就会结束,Worker自己就会主动的去除掉在线程池中的应用,进而被回收掉并退出。这个方法实际上最终就是开启了新的线程去执行任务。

佐杰的博客 1133

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

线程池执行任务的流程是咋么样的?

ThreadPoolExecutor是Java线程池中最核心的类之一,它能够保证线程池按照正常的业务逻辑执行任务,并通过原子方式更新线程池每个阶段的状态。ThreadPoolExecutor类中存在一个workers工作线程集合,用户可以向线程池中添加需要执行的任务,workers集合中的工作线程可以直接执行任务,或者从任务队列中获取任务后执行。ThreadPoolExecutor类中提供了整个线程池从创建到执行任务,再到消亡的整个流程方法。

chengxuyuanlaow的博客 1317

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

上一篇: 最强 IntelliJ IDEA 2022.3 发布,这次不追了。。。
下一篇: Java 8 Stream 之 collect() 的奇技淫巧
公众号-芋道源码
博客等级 码龄10年 1634粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值