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

来源:一个线程池中的线程异常了,那么线程池会怎么处理这个线程? - 反光的小鱼儿 - 博客园

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

目录

  • 线程池常用问题
    • 不允许使用的原因
  • 测试流程
    • 测试用例
    • 抛出堆栈异常为啥对了一半?
    • 怎么拿到submit的异常堆栈?
  • 源码查看
    • 执行executes方法时
    • 执行submit方法时
    • 不影响其他线程任务
    • 这个线程会被放回线程池为啥错了
  • 结论
    • 1、当执行方式是execute时,可以看到堆栈异常的输出
    • 2、当执行方式是submit时,堆栈异常没有输出。但是调用Future.get()方法时,可以捕获到异常
    • 3、不会影响线程池里面其他线程的正常执行
    • 4、线程池会把这个线程移除掉,并创建一个新的线程放到线程池中
  • 源码执行流程
    • execute源码执行流程
    • submit源码执行流程


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

回到顶部

线程池常用问题

了解JDK Executors线程池吗?
知道JDK提供了哪些默认的实现吗?
看过阿里巴巴java开发手册吗?知道为啥不允许使用默认的实现吗?
你们没有用默认的吧?那来介绍一下你们自定义线程池的几个常用参数呗?
你这个几个参数的值是怎么得来的呀?算出来的?怎么算出来的?
线程池里面的任务是IO密集型的还是计算密集型的呢?
好,现在我们有一个自定义线程池了,来说一下你这个线程池的工作流程呗?
那你这个线程池满了怎么办呀?拒绝?咋拒绝?有哪些拒绝策略呢?
别紧张,随便说两个就行。
......
回到开始说的阿里巴巴java开发手册不允许使用默认实现,你回答说可能会引起OOM,那我们聊聊JVM吧

不允许使用的原因

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors各个方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor:
  主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool:
  主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

回到顶部

测试流程

测试用例

正在上传…重新上传取消​

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;public class ExecutorsTest {public static void main(String[] args) throws Exception {ThreadPoolTaskExecutor executor = init();executor.execute(() -> sayHi("execute"));Thread.sleep(1000);executor.submit(() -> sayHi("submit"));}public static void sayHi(String name) {String printStr = "thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name;System.out.println(printStr);throw new RuntimeException(printStr + " error!!!");}private static ThreadPoolTaskExecutor init() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setThreadNamePrefix("thread_");executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(1000);executor.setKeepAliveSeconds(30);executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();;return executor;}
}

正在上传…重新上传取消​

抛出堆栈异常为啥对了一半?

从执行结果我们看出

当执行方式是execute时,可以看到堆栈异常的输出。
当执行方式是submit时,堆栈异常没有输出。

怎么拿到submit的异常堆栈?

 所以,现在知道为什么回答:抛出堆栈异常只对了一半吧。
execute方法执行时,会抛出(打印)堆栈异常。
submit方法执行时,返回结果封装在future中,如果调用future.get()方法则必须进行异常捕获,从而可以抛出(打印)堆栈异常。
你以为这一部分写到这里就完事了?那不行啊,你心里没有一个疑问吗?为啥execute直接抛出异常,submit没有直接抛出异常呢?

回到顶部

源码查看

执行executes方法时

java.util.concurrent.ThreadPoolExecutor#runWorker中抛出了异常:

 在_java.lang.ThreadGroup#uncaughtException_进行了异常处理:

 这个uncaughtException是何许人也,看java doc上咋说的:

 这个方法是JVM调用的,我们只需要指定我们想要的处理方式即可。
那我们怎么指定呢:

正在上传…重新上传取消​

//直接new Thread()的时候
Thread t=newThread();
t.setUncaughtExceptionHandler(newThread.UncaughtExceptionHandler()
{public void uncaughtException(Thread t, Throwable e){//根据业务场景,做你想做的 }
});
//线程池的时候
ExecutorService threadPool = Executors.newFixedThreadPool(1, thread -> {
Thread t =newThread(thread);
t.setUncaughtExceptionHandler((t1, e) ->
System.out.println("根据业务场景,做你想做的:"+ e.getMessage()));return;}
);

正在上传…重新上传取消​

执行submit方法时

 其本质也是调用了execute方法,所以它还是回到_java.util.concurrent.ThreadPoolExecutor#runWorker_方法:

 向前,继续跟进去看看:

 _java.util.concurrent.FutureTask#setException_干啥了啊,瞅一眼:

 我们马上走向最终的真相:

 好了,第一个议题【抛出堆栈异常为啥对了一半?】讨论完毕。在源码里面走了一趟,现在我们可以给出这一部分的满分答案了。

不影响其他线程任务

这一部分我们直接上代码,运行起来看结果吧:

 代码和运行结果是不会骗人的:
线程池中一个线程异常了后,不影响其他线程任务
大家注意线程名称这个细节:1,2,3,4,6。魔鬼都在细节里啊,这个点我下面会讲,先在这里把问题抛出来:我就纳闷了,怎么没有5啊?!

这个线程会被放回线程池为啥错了

 

 5号线程去哪里了?

 new Worker()方法会告诉你:5去哪里了。

 再配上这张由我这个灵魂画师亲自操刀画的图,一起食用,味道更佳:

 现在知道为啥:我回答这个线程会被放回线程池为啥全错了吧。还附带送你一个线程名称变化的细节。

回到顶部

结论

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

1、当执行方式是execute时,可以看到堆栈异常的输出

原因:ThreadPoolExecutor.runWorker()方法中,task.run(),即执行我们的方法,如果异常的话会throw x;所以可以看到异常。

2、当执行方式是submit时,堆栈异常没有输出。但是调用Future.get()方法时,可以捕获到异常

原因:ThreadPoolExecutor.runWorker()方法中,task.run(),其实还会继续执行FutureTask.run()方法,再在此方法中c.call()调用我们的方法,
如果报错是setException(),并没有抛出异常。当我们去get()时,会将异常抛出。

3、不会影响线程池里面其他线程的正常执行

4、线程池会把这个线程移除掉,并创建一个新的线程放到线程池中

当线程异常,会调用ThreadPoolExecutor.runWorker()方法最后面的finally中的processWorkerExit(),会将此线程remove,并重新addworker()一个线程。

回到顶部

源码执行流程

execute源码执行流程

1、开始执行任务,新增或者获取一个线程去执行任务(比如刚开始是新增coreThread去执行任务)。执行到task.run()时会去执行提交的任务。
      如果任务执行失败,或throw x抛出异常。
2、之后会到finally中的afterExecute()扩展方法,我们可以扩展该方法对异常做些什么。
3、之后因为线程执行异常会跳出runWorker的外层循环,进入到processWorkerExit()方法,此方法会将执行任务失败的线程删除,并新增一个线程。
4、之后会到ThreadGroup#uncaughtException方法,进行异常处理。
     如果没有通过setUncaughtExceptionHandler()方法设置默认的UncaughtExceptionHandler,就会在uncaughtException()方法中打印出异常信息。

submit源码执行流程

1、将传进来的任务封装成FutureTask,同样走execute的方法调用,然后直接返回FutureTask。
2、开始执行任务,新增或者获取一个线程去执行任务(比如刚开始是新增coreThread去执行任务)。
3、执行到task.run()时,因为是FutureTask,所以会去调用FutureTask.run()。
4、在FutureTask.run()中,c.call()执行提交的任务。如果抛出异常,并不会throw x,而是setException()保存异常。
5、当我们阻塞获取submit()方法结果时get(),才会将异常信息抛出。当然因为runWorker()没有抛出异常,所以并不会删除线程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/497062.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习:技术原理、迭代路径与局限

来源:36氪作者:何沛宽本文尝试复盘梳理深度学习目前的技术要点,深度学习中模型迭代的方向,以及改进后存在的局限。第一部分:深度学习技术基本要素:神经元、神经网络、分类器、可视化框架在深度学习领域&…

简单而直接的Python web 框架:web.py

From:https://www.oschina.net/question/5189_4306 Web.py github 地址:https://github.com/webpy/webpy https://pypi.python.org/pypi/web.py Web.py Cookbook 简体中文版:http://webpy.org/cookbook/index.zh-cn web.py 0.3 新…

从寻找可敬的人类开始,扩展未来人类生存的8个维度

来源:资本实验室作者:李鑫从小村庄到大城市,从国内到国外,从地球到月球,从太阳系到银河系……什么样的距离才是最远的距离?从地球的内部,到每一个原子,再到我们的情绪,哪…

开源 Python网络爬虫框架 Scrapy

开源 Python 网络爬虫框架 Scrapy:http://blog.csdn.net/zbyufei/article/details/7554322 介绍 所谓网络爬虫,就是一个在网上到处或定向抓取数据的程序,当然,这种说法不够专业,更专业的描述就是,抓取特定网…

微服务架构设计模式~为应用程序定义微服务架构

为应用程序定义微服务架构 第一步:定义系统操作 第二步:定义服务 第三步:定义服务API和协作方式 第一步:定义系统操作 第二步:定义服务 第三步:定义服务API和协作方式

用 Python 爬虫框架 Scrapy 爬取心目中的女神

From :http://www.cnblogs.com/wanghzh/p/5824181.html 本博文将带领你从入门到精通爬虫框架 Scrapy,最终具备爬取任何网页的数据的能力。 本文以校花网为例进行爬取,校花网:http://www.xiaohuar.com 让你体验爬取校花的成就感。 …

微服务架构设计模式~识别系统操作

第一步:创建由关键类组成的抽象领域模型,这些关键类提供用于描述系统操作的词汇表; 第二步:确定系统操作,并根据领域模型描述每个系统操作的行为 领域模型主要源自用户故事中提及的名词,系统操作主要来自用…

Facebook、微软、谷歌三大研究巨头齐聚首,共同探讨人工智能发展现状和趋势

作者: 思颖、李诗概要:日前 AAAS 在 reddit 上组织了一场问答,Facebook 人工智能研究院 Yann LeCun,微软研究院院长 Eric Horvitz,谷歌研究总监 Peter Norvig 共同出席此次活动,回答了观众提出的一系列问题…

《大话设计模式》Python 版代码实现

From:http://www.cnblogs.com/wuyuegb2312/archive/2013/04/09/3008320.html 一、简单工厂模式 模式特点:工厂根据条件产生不同功能的类。 程序实例:四则运算计算器,根据用户的输入产生相应的运算类,用这个运算类处理具…

LeCun亲授的深度学习入门课:从飞行器的发明到卷积神经网络

Root 编译整理量子位 出品 | 公众号 QbitAI深度学习和人脑有什么关系?计算机是如何识别各种物体的?我们怎样构建人工大脑?这是深度学习入门者绕不过的几个问题。很幸运,这里有位大牛很乐意为你讲解。2月6日,UCLA&#…

微服务架构设计模式~根据业务能力进行服务拆分

业务能力定义了一个组织的工作 组织的业务能力通常是指这个组织的业务是做什么,它们通常是稳定的。 与之相反,组织采用何种方式来实现它的业务能力,是随着时间不断变化的。 识别业务能力 一个组织有哪些业务能力,是通过对组织的…

微服务架构设计模式~根据子域进行服务拆分

子域 领域驱动为每个子域定义单独的领域模型。子域是领域的一部分,领域是DDD中用来描述应用程序问题域的一个术语。识别子域的方式跟识别业务能力一样:分析业务并识别业务的不同专业领域,分析产出的子域定义结果也会跟业务能力非常接近。 限…

高通:全球NB-IoT/eMTC最新现状

来源:5G概要:全球NB-IoT/eMTC最新现状行业观察未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能,互联网和脑科学交叉研究机构。由互联网进化论作者,计算机博士刘锋与中国科学院虚拟经济与数据科学研究中心石勇、刘…

2018年看好这些半导体企业

来源:钜亨网对半导体产业来说,去年是一个大年,无论哪个领域,都挣得盘满钵满。进入了2018,半导体产业将会面临哪些新状况?让我们来盘点一下!DRAM今年供需稳定记忆体厂商持续获利的好年DRAM价格走…

AI黑箱:我们要用AI解释AI?

来源:亿欧概要:AI算法对人类生活的影响越来越大,但它们内部的运作往往是不透明的,人们对这种技术的工作方式也愈加感到担忧。AI算法对人类生活的影响越来越大,但它们内部的运作往往是不透明的,人们对这种技…

1053 Path of Equal Weigh(甲级)

1053 Path of Equal Weight (30分) Given a non-empty tree with root R, and with weight W ​i ​​ assigned to each tree node T ​i ​​ . The weight of a path from R to L is defined to be the sum of the weights of all the nodes along the path from R to any l…

美媒盘点DARPA的自然仿生项目

转自:“国防科技要闻”(ID:CDSTIC)作者:军事科学院军事科学信息研究中心 袁政英为了提高无人机蜂群效能,美空军已经开展对蝙蝠的研究。而DARPA的“生物技术办公室”也在试验一系列仿生项目,以获…

浙江将建设超级高速公路,全面支持自动驾驶

来源:科技日报作者:江耘将建设的超级高速公路将具备智能、快速、绿色、安全的四大要素。浙江省要建设全国首条超级高速公路的说法于近日得到了官方证实。记者了解到,将建设的超级高速公路是已经分段批复的杭甬复线高速公路——杭绍甬高速公路…

Codeforces Round 917 (Div. 2)(A~D)(又是数学题)

A - Least Product 题意&#xff1a; 思路&#xff1a;若有奇数个负数&#xff0c;则不需要任何操作。若存在0&#xff0c;也不需要任何操作。其余情况将任意一个数改为0即可。 #include <bits/stdc.h> using namespace std; void solve() {int n;cin >> n;int …

权威发布:新一代人工智能发展白皮书(2017)

来源&#xff1a;机器人大讲堂指导单位、专家顾问及编写人员顾 问潘云鹤 中国工程院院士指导单位工业和信息化部信息化和软件服务业司指导委员会谢少锋 工信部信软司司长李冠宇 工信部信软司副司长徐晓兰 中国电子学会副理事长兼秘书长张宏图 中国电子学会总部…