ThreadPoolExecutor 学习笔记

JDK版本:AdoptOpenJDK 11.0.10+9

参考:传送门

1 基本概念

ThreadPoolExecutorj.u.c 提供的实现了 ExecutorService 接口的实现类,Executors 提供的很多线程池都是基于它来创建的。

ThreadPoolExecutor 并没有直接实现 ExecutorService 接口,而是继承了 AbstractExecutorService 抽象类,结构如下:

在这里插入图片描述

AbstractExecutorService 封装了线程池的一些通用逻辑,如果想自定义一个线程池,也可以通过继承这个抽象类来实现。

ThreadPoolExecutor 只是其中一种实现罢了:

public class ThreadPoolExecutor extends AbstractExecutorService {
   
    ......
}

2 ThreadPoolExecutor 基本元素

线程池的一般设计原理

  • 待执行的任务首先保存在任务队列中;
  • 线程池分配一个空闲线程,从任务队列中取出一个待执行的任务,执行它;
  • 线程池中没有空闲线程的时候,所有任务(包括新进来的任务)都将在任务队列中等待。

2.1 构造函数

一共有4个构造函数,前三个都是由最后一个演化而来的:

    // 第一个构造函数
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
   
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

    // 第二个构造函数
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
   
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }

    // 第三个构造函数
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
   
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

    /**
     * 第四个构造函数(重点)
     * 使用给定的参数创建线程池
     *
     * @param corePoolSize    核心线程池允许创建的最大线程数
     * @param maximumPoolSize 当任务队列满了,线程池允许创建的最大线程数
     * @param keepAliveTime   空闲线程的存活时间
     * @param unit            keepAliveTime的单位
     * @param workQueue       任务队列,保存已经提交但尚未被执行的任务
     * @param threadFactory   线程工厂(用于指定如果创建一个线程)
     * @param handler         拒绝策略(当任务太多导致工作队列满时的处理策略)
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
   
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

注意区分 corePoolSizemaximumPoolSize

  • corePoolSize 是指核心线程池中允许创建的最大工作线程的数量。当任务队列还没有满的时候,新来一个任务将会新建一个工作线程,直到达到 corePoolSize 就不会再创建线程了,后边新来的任务将会在队列中排队。
  • 当任务队列满了,线程池可以继续创建新的工作线程来处理任务,直到工作线程的总数达到 maximumPoolSize 时就不再创建新的工作线程了。

2.2 线程池的状态

ThreadPoolExecutor 通过一个 AtomicInteger 类型的变量 ctl 来记录 线程池的状态工作线程数

低 29 位:工作线程数

高 3 位:线程池状态

    // 状态变量ctl
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

    private static final int COUNT_BITS = Integer.SIZE - 3;

    // 最大线程数 2^29 - 1
    private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;

    // 线程池5种状态
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

一共定义了 5 种线程池状态:

  • RUNNING:能够接收新任务,并且正在处理任务队列中的任务。
  • SHUTDOWN:不接收新任务,但会去处理任务队列中已经存在的任务。
  • STOP:不接收新任务,也不处理任务队列中已经存在的任务,同时中断正在执行的任务。
  • TIDYING:当所有任务都已终止,工作线程数变为 0 ,线程池会变为 TIDYING 状态,并且会调用钩子函数 terminated()
  • TERMINATEDterminated() 函数执行之后,,线程池会变为 TERMINATED 状态。

如下图所示:

在这里插入图片描述

5个状态数值大小:RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED

2.3 Worker 工作线程

ThreadPoolExecutor 中通过内部类 Worker 来代表工作线程的,Worker 类继承 AQS,实现了 Runnable 接口。

并且,通过一个 HashSet 来保存线程池中所有的工作线程。

    // 工作线程的集合
    private final HashSet<Worker> workers = new HashSet<>();

Worker 源码如下:

    private final class Worker extends AbstractQueuedSynchronizer implements Runnable
    {
   
        // 序列化ID,虽然用不到
        private static final long serialVersionUID = 6138294804551838833L;

        // 关联的线程
        final Thread thread;
        
        // 
        Runnable firstTask;
        
        // 
        volatile long completedTasks;

        // 构造函数,工作线程的状态初始化为-1
        Worker(Runnable firstTask) {
   
            setState(-1);
            this.firstTask = firstTask;
            this.thread = getThreadFactory(</
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值