Java线程池---ThreadPoolExecutor解析

ThreadPoolExecutor属性介绍

ThreadPoolExecutor中的ctl变量中已经解释了线程池中ctl变量中,高3位代表线程池当前的状态,而低28位表示线程池中线程的总数。

ThreadPoolExecutor执行任务

而了解了线程池ctl变量的意义后,在线程池中,会调用execute函数来执行任务,在execute函数解析中,可以看到线程池在有任务需要被执行的时候会判断:

  1. 核心线程未达到corePoolSize的时候,会将被执行的任务作为firstTask,并且新起Worker创建Thread执行任务。
  2. 如果超过了核心线程,则会判断当前线程池是否正处于Running状态,如果处于的话,那么则将Task插入到队列中
  3. 如果插入队列成功的话,那么会重新再检查一次当前状态,如果当前状态在其他线程改成了非Running的话,那么则需要从队列中把刚加入的Task remove掉,如果从队列Remove成功了,那么就会执行Reject拒绝策略。
  4. 如果remove失败,或者处于Running状态的话,那么就会判断,当前的Worker是否为0,如果为0的话,那么就会以非核心线程的方式,去执行这个Task
  5. 如果当前线程没有处于Running状态,或者插入队列失败的话,那么就会尝试以当前Task作为firstTask,非核心线程的方式添加Worker执行这个任务,如果添加Worker失败了的话,那么就会执行Reject策略。

ThreadPoolExecutor添加线程

而在AddWorker方法中,会返回是否成功创建Worker

  1. 判断线程池当前状态,如果比SHUTDOWN状态要大的话,那么直接返回false,如果是SHUTDOWN的话,那么只会判断当前任务队列中是否还有任务,而新添加的任务则不会管,如果队列中还有任务的话,那么就会在线程池停止运行前,将队列中剩余的任务执行完。
  2. 检查当前WorkerCount是否合法,如果不合法,即判断是否是核心线程,如果是的话,那么判断WorkerCount是否大于corePoolSize,如果不是核心线程的话,那么则判断WorkerCount是否大于maximumPoolSize,如果不合法的话,那么直接返回false。
  3. 如果满足了线程池大小要求,那么就会尝试通过CAS操作增加WorkerCount,如果CAS操作失败了的话,那么就重新检查当前线程池状态。
  4. 如果CAS增加线程总数成功的话,那么就会创建一个Worker对象,然后再检查一次线程池当前状态,如果当前状态大于SHUTDOWN,或者是SHUTDOWN但是firstTask不为空的时候,才会调用decrementWorkerCount减少WorkerCount,并且返回false。
  5. 如果正常运转的话,那么就会将新创建的Worker添加到WorkerSet中,并且启动Thread,返回true。

ThreadPoolExecutor中各个线程处理任务

在线程启动后,会执行runWorker方法,会循环获取Task,然后执行Task中的run方法。

  1. 首先设置completedAbruptly为true,表示Worker在执行任务的时候异常退出了。后面如果任务全部执行完了,没有异常的话,那么就会将completedAbruptly设置成false。
  2. 判断firstTask是否存在,如果存在则执行,如果不存在的话,那么则获取任务队列中的Task,然后准备开始执行
  3. 在执行之前会调用beforeExecute来告知子类,任务即将被开始执行
  4. 接着执行任务,无论执行任务的过程中,是否出现异常,都会执行afterExecute方法告知子类,任务执行完毕,而在该方法中,如果出现异常,则会将异常通过参数的方式,告知子类,在执行该任务的过程中,发生了某个异常。一旦出现异常,线程会立马终止。
  5. 如果所有任务执行完后,没有出现异常,则会将completedAbruptly设置成false

ThreadPoolExecutor中Worker任务处理完成后退出

在Worker执行完所有任务或者在执行任务的时候发生了异常,会处理工作线程退出,来判断在当前Worker执行完任务之后,是否还需要再重新启动一个新的Worker来处理新任务。

  1. 判断是否是异常中断,如果是异常中断的话,则需要将WorkerCount减一
  2. 将Worker从WorkerSet中移除
  3. 调用tryTerminate,尝试终止线程池
  4. 判断线程池当前状态是否小于STOP,如果是的话,那么则判断是否是异常终止的,如果是异常终止的Worker,则直接调用addWorker,看是否还需要添加新的Worker去处理剩余的Task
  5. 如果不是异常终止的,那么则判断当前还需要多少个Worker来处理任务,如果当前的Worker总数超过了最少要的Worker总数的话,就直接返回了,因为有足够多的Worker可以处理Task,如果Worker不够的话,那么就调用addWorker尝试添加新的Worker去处理任务。

ThreadPoolExecutor退出

终止线程池的方法有两个ShutDown以及ShutDownNow,调用完之后,线程池就开始进入关闭的状态了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Jimoer

JVM学习记录-线程安全与锁优化(一)

线程:程序流执行的最小单元。线程是比进程更轻量级的调度执行单位,线程的引入,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件I...

8120
来自专栏逸鹏说道

C# 温故而知新: 线程篇(二) 上

线程池和异步线程 目录: 1 什么是CLR线程池? 2 简单介绍下线程池各个优点的实现细节 3 线程池ThreadPool的常用方法介绍 4 简单理解下异步线程...

32890
来自专栏chenssy

【死磕Java并发】—–Java内存模型之happens-before

在上篇博客(【死磕Java并发】—–深入分析volatile的实现原理)LZ提到过由于存在线程本地内存和主内存的原因,再加上重排序,会导致多线程环境下存在可见性...

34790
来自专栏好好学java的技术栈

java大公司后端多线程面试题最强分享

抢占式。一个线程用完CPU之后,操作系统会根据线程优先级、线程饥饿情况等数据算出一个总的优先级并分配下一个时间片给某个线程执行。

19110
来自专栏GreenLeaves

JS模块加载系统设计V1

一、require模块 +function() { var path = location.protocol + "//" + loca...

21250
来自专栏小勇DW3

Java多线程面试题整理 1) 什么是线程?

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速。比...

40620
来自专栏日常分享

Struts2 学习笔记

4)核心控制器SturtsPrepareAndExecuteFilter实际上是一个Servlet过滤器,需再Web.xml中配置。 5)Action是由用户定...

15420
来自专栏芋道源码1024

【死磕Java并发】—–Java内存模型之happens-before

在上篇博客(【死磕Java并发】—–深入分析volatile的实现原理)LZ提到过由于存在线程本地内存和主内存的原因,再加上重排序,会导致多线程环境下存在可见性...

30750
来自专栏从零开始学自动化测试

pytest文档14-函数传参和fixture传参数request

为了提高代码的复用性,我们在写用例的时候,会用到函数,然后不同的用例去调用这个函数。 比如登录操作,大部分的用例都会先登录,那就需要把登录单独抽出来写个函数,其...

51920
来自专栏机器学习从入门到成神

各大公司Java后端开发面试题总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

41520

扫码关注云+社区

领取腾讯云代金券