设为首页 加入收藏

TOP

Java - ThreadPoolExecutor线程池分析(二)
2023-09-09 10:25:58 】 浏览:111
Tags:Java ThreadPoolExecutor 程池分
核心属性 // 线程池的状态: ctl的高3位,表示线程池状态 // 工作线程的数量: ctl的低29位,表示工作线程的个数 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); // Integer.SIZE: 获取Integer的bit位个数 // 声明一个常量: COUNT_BITS = 29 private static final int COUNT_BITS = Integer.SIZE - 3; // CAPACITY就是当前工作线程能记录的工作线程的最大个数 private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 线程池状态表示 // 当前五个状态中,只有RUNNING状态表示线程池正常,可以正常接收任务处理 // 111: 代表RUNNING状态,RUNNING可以处理任务,并且处理阻塞队列中的任务 private static final int RUNNING = -1 << COUNT_BITS; // 000: 代表SHUTDOWN状态,不会接收新任务,正在处理的任务正常进行,阻塞队列中的任务也会处理完 private static final int SHUTDOWN = 0 << COUNT_BITS; // 001: 代表STOP状态,不在接收新任务,正在处理的任务会被中断,阻塞队列中的任务不在处理 private static final int STOP = 1 << COUNT_BITS; // 010: 代表TIDYING状态,这个状态是SHUTDOWN或者STOP转换过来的,代表线程池马上关闭,过度状态 private static final int TIDYING = 2 << COUNT_BITS; // 011: 代表TERMINATED状态,这个状态是TIDYING转换过来的,转换过来需要执行terminated方法 private static final int TERMINATED = 3 << COUNT_BITS; // 下面方法是帮助运算ctl值的,需要传入ctl // 基于&运算的特点,保证获取ctl的高3位的值 private static int runStateOf(int c) { return c & ~CAPACITY; } // 基于&运算的特点,保证获取ctl的低29位的值 private static int workerCountOf(int c) { return c & CAPACITY; } // runStateOf 和 workerCountOf 方法都是拆包 // 基于|运算的特点,对线程池状态rs和线程个数wc进行封装 private static int ctlOf(int rs, int wc) { return rs | wc; }

 线程池的转换方式:

ThreadPoolExecutor中的execute方法

execute方法是提交任务到线程池的核心方法。

execute源码解析:

//  提交执行任务
//  command 就是提交过来的任务
public void execute(Runnable command) {
    //  提交的任务不能为null  健壮性判断
    if (command == null)
        throw new NullPointerException();
    //  获取核心属性ctl值,用于后续判断
    int c = ctl.get();
    //  如果工作线程个数小于核心线程数
    //  满足要求,添加核心工作线程
    if (workerCountOf(c) < corePoolSize) {
        //  addWorker(任务,是否是核心线程) ture: 核心线程,false:非核心线程
        //  addWorker返回true: 代表添加工作线程成功
        //  addWorker返回false: 代表添加工作线程失败
        //  addWorker中会基于线程池状态,以及工作线程个数判断,查看能否添加工作线程
        if (addWorker(command, true))
            //  工作线程构建出来了,任务也交给command去处理了
            return;
        //  说明线程池状态或者是工作线程个数发生了变化,导致添加失败,需要重新获取ctl值
        c = ctl.get();
    }
    //  添加核心工作线程失败后
    //  先判断线程池状态是否是RUNNING状态,如果是正常基于阻塞队列的offer方法,将任务添加到阻塞队列
    if (isRunning(c) && workQueue.offer(command)) {
        //  如果任务添加到阻塞队列成功,走if内部
        //  如果任务在丢到阻塞队列之前,线程池状态发生改变了
        //  重新获取ctl
        int recheck = ctl.get();
        //  如果线程池的状态不是RUNNING状态,将任务从阻塞队列中移除
        if (! isRunning(recheck) && remove(command))
            //  并且直接拒绝策略
            reject(command);
        //  在这,说明阻塞队列有我刚放进去的任务
        //  查看一下工作线程数是不是0个
        //  如果工作线程为0个,需要添加一个非核心工作线程去处理阻塞队列中的任务
        //  发生这种情况有两种:
        //  1. 构建线程池时,核心线程数可以是0个
        //  2. 即使有核心线程,可以设置核心线程也允许超时,设置allowCoreThreadTimeOut(默认false)为ture
        else if (workerCountOf(recheck) == 0)
            //  为了避免阻塞队列中的任务堆积,添加一个非核心线程去处理
            addWorker(null, false);
    }
    //  任务添加到阻塞队列失败
    //  构建一个非核心工作线程
    //  如果添加非核心工作线程成功,直接完成
    else if (!addWorker(command, false))
        //  添加失败,执行拒绝策略
        reject(command);
}

execute方法流程图:

 ThreadPoolExecutor中的addWorker方法

addWorker方法中主要分为两大块:

  • 第一块:校验线程池的状态以及工作线程个数
  • 第二块:添加工作线程并且启动工作线程
//  校验和添加启动工作线程
private boolean addWorker(Runnable firstTask, boolean core) {
    //  =======================第一块====================
    //  外层for循环在校验线程池的状态
    //  内层for循环是在校验工作线程的个数

    //  retry是给外层for循环添加的一个标记,为了方便在内层for循环跳出到外层for循环
    retry:
    for (;;) {
        //  获取ctl
        int c = ctl.get();
        //  拿到ctl的高3位的值
        int rs = runStateOf(c);

        // =====================线程池状态判断==========================
        //  如果线程池状态是SHUTDOWN,并且此时阻塞队列有任务,工作线程为0,则添加一个工作线程去处理阻塞队列的任务
首页 上一页 1 2 3 4 5 6 下一页 尾页 2/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇简述Spring Cache缓存策略 下一篇14、Spring之基于注解的声明式事务

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目