还不懂「ThreadPoolExecutor」?

455 阅读2分钟

这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战

线程池

好处/解决的问题

  • 简而言之就是可复用,不用每次去new一个线程来执行,线程的创建和销毁都是非常消耗资源的
  • 一种节制,因为线程池可以限制我们的线程个数,也可以动态新增 -其他它主要内部有一个成员变量ctl是一个原子的Integer变量,来记录线程池状态和个数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

类图如下

image.png

源码分析

execute

  • execute是用来提交任务 command 到线程池进行执行。

image.png

  1. 判断如果任务为空,那么久抛出异常
  2. 获得当前线程池的状态
  3. 如果当前线程池中的线程个数小于corePoolSize那么就要开启新线程运行
  4. 如果线程池处于RUNNING,那么久添加任务到阻塞队列
private final BlockingQueue<Runnable> workQueue;

4.1 第二次检查

4.2 如果没有处于RUNNING状态,那么久从队列中删除任务,并且执行拒绝策略

4.3 最后都不满足,那么如果当前线程池为空,则添加一个线程

  1. 如果队列满了,那么就新增加线程,如果新增失败则执行拒绝策略

addWorker新增线程方法

image.png 6. 检查队列是否为空(只在必要时候)

  1. 循环CAS增加线程个数

7.1 如果线程数超过限制则false

7.2 CAS增加线程个数,并发条件只有一个线程成功

7.3 CAS失败,那么查看线程池状态是否变化,如果变化了,则调到外层循环重新尝试获取线程池的状态,否则内层循环重新CAS

  1. 循环过后,这里就是CAS已经成功 8.1 创建worker

8.2 加上独占锁,为了实现workers同步,因为可能有多个线程同时调用了线程池的excute的方法

8.3 重新检查线程池状态,避免在获得独占锁前调用shutdown接口