前言

最近看到crossoverJie的一篇文章:一个线程罢工的诡异事件

首先感谢原作者的分享,自己获益匪浅。然后是回想到自己的一次面试经历,面试官提问了线程池中的线程出现了异常该怎样捕获?会导致什么样的问题?

示例代码

public class ThreadPoolException {
private final static Logger LOGGER = LoggerFactory.getLogger(ThreadPoolException.class); public static void main(String[] args) throws InterruptedException {
ExecutorService execute = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); execute.execute(new Runnable() {
@Override
public void run() {
LOGGER.info("=====11=======");
}
}); TimeUnit.SECONDS.sleep(5);
execute.execute(new Run1());
} private static class Run1 implements Runnable {
@Override
public void run() {
int count = 0;
while (true) {
count++;
LOGGER.info("-------222-------------{}", count); if (count == 10) {
System.out.println(1 / 0);
try {
} catch (Exception e) {
LOGGER.error("Exception",e);
}
} if (count == 20) {
LOGGER.info("count={}", count);
break;
}
}
}
}
}

上面的代码是原作者本地调试的一个代码,这里我也大致交代下情形:

  1. 首先是启动main方法看最终执行现象

这里直接抛异常了,by zero。看到底层是ThreadPoolExecutor 1149行抛出的。

查看线程dump,发现线程池中的线程此时处于WAITING状态

  1. 源码追踪

    这里就需要弄清楚为何会出现WAITING状态,所以我们需要一步步追踪源码。

    我们可以在抛异常的地方打断点,然后一步步跟踪:

在执行1149行代码由于抛了异常,所以继续执行finally中processWorkerExit方法:

processWorkerExit中主要做了两件事,worker remover和addWorker。线程池中的任务都会被包装为一个内部 Worker 对象执行。不清楚的可以参考:Java并发之线程池ThreadPoolExecutor源码学习

最后会执行addWorker,紧接着我们继续往addWorker中去跟,看看里面做了什么操作:

addWorker里面是重新new Worker(), 然后执行worker.start(), 接着我们看下Worker中的start方法:

因为Woker是实现Runnable接口的,所以会执行其run方法,接着往runWorker方法跟踪:

因为此时的Worker是上一步重新new出来的,所以其中的task为空,这时需要继续跟踪getTask()方法:

此时因为线程池的队列中并没有任务,所以这里执行take会一直阻塞,也就有了最开始的那个WAITING的状态了。

到了这里一切都很明了了,源码面前任何妖魔鬼怪都无法藏匿,所以但我们使用线程池的时候一定要注意一异常的捕获和处理。

下一章来详细解读一下如何捕获线程池中的异常。

由于本人水平有限,文章中如果有不严谨的地方还请提出来,愿闻其详。

ThreadPoolExcutor 线程池 异常处理 (上篇)的更多相关文章

  1. ThreadPoolExcutor 线程池 异常处理 (下篇)

    前言 因为这是之前面试的一个题目,所以印象比较深刻,前几天写了一篇文章:ThreadPoolExcutor 线程池 异常处理 (上篇) 中已经介绍了线程池异常的一些问题以及一步步分析了里面的一些源代码 ...

  2. JDK线程池异常处理方式

    1. 抛出异常 execute() java.util.concurrent.ThreadPoolExecutor#runWorker 中抛出,抛出之后经过以下两个步骤: catch块捕获,捕获之后再 ...

  3. JAVA 线程池之Callable返回结果

    本文介绍如何向线程池提交任务,并获得任务的执行结果.然后模拟 线程池中的线程在执行任务的过程中抛出异常时,该如何处理. 一,执行具体任务的线程类 要想 获得 线程的执行结果,需实现Callable接口 ...

  4. 面试必备:Java线程池解析

    前言 掌握线程池是后端程序员的基本要求,相信大家求职面试过程中,几乎都会被问到有关于线程池的问题.我在网上搜集了几道经典的线程池面试题,并以此为切入点,谈谈我对线程池的理解.如果有哪里理解不正确,非常 ...

  5. Java线程池面试

    New Thread的弊端 每次new Thread会新建对象,性能差 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或OOM 缺少更多功能,如更多执行.定期执行.线 ...

  6. 美团动态线程池实践思路开源项目(DynamicTp),线程池源码解析及通知告警篇

    大家好,这篇文章我们来聊下动态线程池开源项目(DynamicTp)的通知告警模块.目前项目提供以下通知告警功能,每一个通知项都可以独立配置是否开启.告警阈值.告警间隔时间.平台等,具体代码请看core ...

  7. JAVA线程池ScheduledExecutorService周期性地执行任务 与单个Thread周期性执行任务的异常处理

    本文记录: 1,使用ScheduledExecutorService的 scheduleAtFixedRate 方法执行周期性任务的过程,讨论了在任务周期执行过程中出现了异常,会导致周期任务失败. 2 ...

  8. java 线程池第一篇 之 ThreadPoolExcutor

    一:什么是线程池? java 线程池是将大量的线程集中管理的类,包括对线程的创建,资源的管理,线程生命周期的管理.当系统中存在大量的异步任务的时候就考虑使用java线程池管理所有的线程.减少系统资源的 ...

  9. 线程池:ThreadPoolExcutor源码阅读

    ThreadPoolExcutor源码流程图:(图片较大,下载再看比较方便) 线程池里的二进制奥秘 前言: 线程池的五种状态state(RUNNING.SHUTDOWN.STOP.TIDYING.TE ...

随机推荐

  1. Linux下的Hadoop安装(本地模式)

    系统为CentOS 6.9,Hadoop版本2.8.3,虚拟机VMware Workstation 主要介绍Linux虚拟机安装.环境配置和Hadoop本地模式的安装.伪分布式和Windows下的安装 ...

  2. IIS7.0提示“请求筛选模块被配置为拒绝包含双重转义序列的请求”处理办法

    请求筛选模块被配置为拒绝包含双重转义序列的请求.HTTP 错误 404.11 - Not Found 解决办法: 1.单击 开始 . 在 开始搜索 框中, 键入 Notepad. 右击 记事本 , 然 ...

  3. Xamarin SQLite教程Xamarin.iOS项目添加引用

    Xamarin SQLite教程Xamarin.iOS项目添加引用 使用直接方式访问SQLite数据库,需要将System.Data和Mono.Data.SQlite库导入到创建的项目中.下面将分别讲 ...

  4. padding和margin设置成百分比

    Margin和Padding是我们在网页设计经常使用到的CSS样式,他们分别是间距和填充,一个作用于盒子外面,一个作用于盒子里面,默认的情况下,这些属性的值都会被计算在盒子的面积里面,在网页开发中的流 ...

  5. 数学——Euler方法求解微分方程详解(python3)

    算法的数学描述图解 实例 用Euler算法求解初值问题 \[ \frac{dy}{dx}=y+\frac{2x}{y^2}\] 初始条件\(y(0)=1\),自变量的取值范围\(x \in [0, 2 ...

  6. 2006 ACM 求奇数的和

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2006 注意 sum=1,写在while 不然每次结果会累积 #include <stdio.h> ...

  7. [CQOI2005]三角形面积并

    [CQOI2005]三角形面积并 题目大意: 求\(n(n\le100)\)个三角形的面积并. 思路: 自适应辛普森法,玄学卡精度可过. 源代码: #include<cmath> #inc ...

  8. [P1034][NOIP2001]一元三次方程求解 (二分)

    二分 #include<bits/stdc++.h> using namespace std; double a,b,c,d; double fc(double x) { )+b*pow( ...

  9. VueJs记录

    v-model是双向绑定,v-bind用来绑定属性,也可以简写成为:

  10. 移动端适配问题px->rem方法

    移动端web页面适配问题 1.引入插件 github地址:https://github.com/re54k/mobileweb-utilities/blob/master/util/mobile-ut ...