十、ThreadPoolExecutor 手撕核心源码

ThreadPoolExecutor核心分析

1、应用方式

  • 只需要构建好 ThreadPoolExecutor 对象即可,传入指定参数
  • 通过 execute 可以把 Runnable 扔进线程池
  • 通过 submit 既可以把 Runnable 扔进线程池,也能把 Callable 扔进线程池,且 Callable 可接返回值
import java.util.concurrent.*;

/**
 * 自定义线程池
 */
public class 自定义线程池 {

    public static void main(String[] args) 
        throws ExecutionException, InterruptedException {
        /**
          * 1、创建自定义线程池
          */
        ThreadPoolExecutor myPool = new ThreadPoolExecutor(
                10, // corePoolSize:核心线程数
                20, // maximumPoolSize:最大线程数
                0L, // keepAliveTime:存活时间
                TimeUnit.MILLISECONDS, // unit:时间单位
                new ArrayBlockingQueue<Runnable>(10), // workQueue:等待队列
                new ThreadFactory(){
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread t = new Thread(r);
                        t.setName("xxx");
                        return t;
                    }
                }, // threadFactory 线程工程
                new RejectedExecutionHandler(){
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        System.out.println("拒绝!不鸟你!");
                    }
                } // handler 拒绝策略
        );

        for (int i = 0; i < 1000; i++) {
            /**
              * 2.1、通过 execute 将线程丢进池子执行(只能丢Runnable)
              */
            int finalI = i;
            myPool.execute(()->{
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "---" + finalI);
            });
            /**
              * 2.2、通过 submit 将线程丢进池子执行
              *(既能丢Runnable也能丢Callable,且Callable可接返回值)
              */
            Future<Object> result = myPool.submit(new Callable<Object>() {
                @Override
                public Object call() throws Exception {
                    return finalI;
                }
            });
            System.out.println("---< 通过 Future 获取的返回值 >--->" + result.get());
        }

        /**
          * 3、关闭线程池
          */
        myPool.shutdown();
    }

}

2、核心参数

int corePoolSize, 					// 核心线程数
int maximumPoolSize, 				// 最大线程数
long keepAliveTime,					// 存活时间
TimeUnit unit,						// 时间单位
BlockingQueue<Runnable> workQueue,	// 阻塞队列
ThreadFactory threadFactory,		// 线程工厂
RejectedExecutionHandler handler	// 拒绝策略

常用 workQueue:

在这里插入图片描述

public interface Queue<E> extends Collection<E> {
    /**
     * 插入》》》
     * 如果可以在不违反容量限制的情况下立即将指定元素插入此队列,则在成功时返回{@code true},
     * 如果当前没有可用空间,则抛出{@code IllegalStateException}
     *
     * @param e 要添加的元素
     * @return {@code true} (由{@link Collection#add}指定)
     * @throws IllegalStateException 如果由于容量限制,此时无法添加元素
     * @throws ClassCastException 如果指定元素的类阻止将其添加到此队列
     * @throws NullPointerException 如果指定的元素为空,并且此队列不允许空元素
     * @throws IllegalArgumentException 如果此元素的某些属性阻止将其添加到此队列
     */
    boolean add(E e);

    /**
     * 插入》》》
     * 如果可以在不违反容量限制的情况下立即将指定元素插入此队列,则将其插入。当使用容量受限队列时,
     * 此方法通常优于{@link#add},后者只能通过抛出异常来插入元素.
     *
     * @param e 要添加的元素
     * @return {@code true} 如果元素已添加到此队列,否则 {@code false}
     * @throws ClassCastException 如果指定元素的类阻止将其添加到此队列
     * @throws NullPointerException 如果指定的元素为空,并且此队列不允许空元素
     * @throws IllegalArgumentException 如果此元素的某些属性阻止将其添加到此队列
     */
    boolean offer(E e);

    /**
     * 头删 ×××
     * 检索并删除此队列的头。此方法与{@link#poll poll}的不同之处在于,如果此队列为空,它将引发异常.
     *
     * @return 这个队列的头
     * @throws NoSuchElementException 如果此队列为空
     */
    E remove();

    /**
     * 头删 ×××
     * 检索并删除此队列的头,如果此队列为空,则返回{@code null}.
     *
     * @return 此队列的头,如果此队列为空,则为{@code null}
     */
    E poll();

    /**
     * 《《《获取头
     * 检索但不删除此队列的头。此方法与{@link#peek peek}的不同之处在于,如果此队列为空,它将引发异常.
     *
     * @return 这个队列的头
     * @throws NoSuchElementException 如果此队列为空
     */
    E element();

    /**
     * 《《《获取头
     * 检索但不删除此队列的头,如果此队列为空,则返回{@code null}.
     *
     * @return 此队列的头,如果此队列为空,则为{@code null}
     */
    E peek();
}

默认提供的 4个 handler:

在这里插入图片描述

public class ThreadPoolExecutor extends AbstractExecutorService {

    /* 预定义的 RejectedExecutionHandler */

    /* 我不管,谁扔进来的谁运行! */
    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

    /* 直接原地爆炸! */
    public static class AbortPolicy implements RejectedExecutionHandler {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

    /* 装傻 */
    public static class DiscardPolicy implements RejectedExecutionHandler {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

    /* 偷摸把列头扔了,尝试新任务的重入 */
    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }
}

3、执行流程

在这里插入图片描述


4、状态

1、线程池核心属性 ctl

public class ThreadPoolExecutor extends AbstractExecutorService {
    /**
     * 主池控制状态ctl是一个包含两个概念字段的原子整数
     *   workerCount:指示有效线程数
     *   runState:指示是否正在运行、关闭等
     *
     * 为了将它们打包成一个整数,我们将 workerCount 限制为
     * (2^29)-1(约5亿)个线程,而不是(2^31)-1(20亿)个其他可
     * 表示的线程。如果将来出现问题,可以将变量更改为原子长,并调整下面
     * 的 移位/掩码 常数。但是,在需要之前,使用int会使代码更快、更简单
     *
     * workerCount 是允许启动和不允许停止的工人数。该值可能暂时不同于
     * 活动线程的实际数量,例如,当 ThreadFactory 在被请求时无法创建
     * 线程时,以及当退出线程在终止之前仍在执行簿记时。用户可见池大小报
     * 告为工作集的当前大小
     *
     * 运行状态提供主要的生命周期控制,具有以下值:
     *   RUNNING:  接受新任务并处理排队的任务
     *   SHUTDOWN: 不接受新任务,但处理排队的任务
     *   STOP:     不接受新任务,不处理排队的任务,
     *             以及中断正在进行的任务
     *   TIDYING:  所有任务都已终止, workerCount 为零,
     *             转换到状态“TIDYING”的线程将运行 
     *             terminated()钩子方法
     *   TERMINATED: terminated() 已经完成
     *
     * 这些值之间的数字顺序很重要,以便进行有序比较。运行状态随时间单调增加,
     * 但不需要达到每个状态。过渡是:
     * RUNNING -> SHUTDOWN
     *    在调用 shutdown() 时,可能隐式地在 finalize() 中
     * (RUNNING or SHUTDOWN) -> STOP
     *    在调用 shutdownNow() 时
     * SHUTDOWN -> TIDYING
     *    当 queue 和 pool 都为空时
     * STOP -> TIDYING
     *    当 pool 为空时
     * TIDYING -> TERMINATED
     *    当 terminated() 钩子方法完成时
     *
     * 等待 awaitTermination() 的线程将在状态达到 TERMINATED 时返回
     *
     * 检测从 SHUTDOWN 到 TIDYING 的转换并不像您希望的那样简单,因为队列
     * 在非空状态后可能会变为空,而在 SHUTDOWN 状态下也可能变为空。但我们
     * 只能在看到队列为空后,看到 workerCount 为 0 时终止(这有时需要重新
     * 检查——见下文)
     */
    // ctl 本质就是一个 int 类型的数值
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    
    // 【常量 29】 : COUNT_BITS = (Integer.SIZE = 32) - 3 
    // ctl 表示两个状态:
    // 1、表示线程池当前状态(高3位)
    // 2、表示线程池当前的工作线程个数(低29位)
    private static final int COUNT_BITS = Integer.SIZE - 3;
    
    // 低29位 存储 【当前的工作线程个数】 最多 2^29 -1
    /** 
     * 1 << 29 = 0010 0000 0000 0000 0000 0000 0000 0000
     *     - 1 = 0001 1111 1111 1111 1111 1111 1111 1111
     * 【高3位 = 111 ==> RUNNING】
     */
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // 高3位 存储 运行状态
    /** 
     * -1 = 1111 1111 1111 1111 1111 1111 1111 1111
     * -1 << 29 = 1110 0000 0000 0000 0000 0000 0000 0000
     * 【高3位 = 111 ==> RUNNING】
     */
    private static final int RUNNING    = -1 << COUNT_BITS;
    /** 
     * 0 = 0000 0000 0000 0000 0000 0000 0000 0000 
     * 0 << 29 = 0000 0000 0000 0000 0000 0000 0000 0000
     * 【高3位 = 000 ==> SHUTDOWN】
     */
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    /** 
     * 1 = 0000 0000 0000 0000 0000 0000 0000 0001 
     * 1 << 29 = 0010 0000 0000 0000 0000 0000 0000 0000
     * 【高3位 = 001 ==> SHUTDOWN】
     */
    private static final int STOP       =  1 << COUNT_BITS;
    /** 
     * 2 = 0000 0000 0000 0000 0000 0000 0000 0010 
     * 2 << 29 = 0100 0000 0000 0000 0000 0000 0000 0000
     * 【高3位 = 010 ==> TIDYING】
     */
    private static final int TIDYING    =  2 << COUNT_BITS;
    /** 
     * 3 = 0000 0000 0000 0000 0000 0000 0000 0011 
     * 3 << 29 = 0110 0000 0000 0000 0000 0000 0000 0000
     * 【高3位 = 011 ==> TERMINATED】
     */
    private static final int TERMINATED =  3 << COUNT_BITS;

    /* ↓↓↓ ctl的装箱和拆箱 ↓↓↓ */
    
    // 计算当前线程池的状态
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    // 计算当前线程池中工作线程的个数
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    private static int ctlOf(int rs, int wc) { return rs | wc; }
    
}

2、线程池状态变换

在这里插入图片描述


5、execute

第一点核心:通过 execute方法,查看到线程池的整体执行流程,以及一些避免并发情况的判断

第二点核心:为什么线程池会添加一个空任务的非核心线程到线程池

public class ThreadPoolExecutor extends AbstractExecutorService {

    /**
     * 在将来的某个时间执行给定的任务。该任务可以在新线程或现有池线程中执行。
     *
     * 如果由于此执行器已关闭或已达到其容量而无法提交任务以供执行,则该任务将
     * 由当前{@code RejectedExecutionHandler}处理。
     *
     * @param command 要执行的任务
     * @throws RejectedExecutionException 如果无法接受任务执行,则由
     * 					{@code RejectedExecutionHandler}自行决定
     * @throws NullPointerException 如果{@code command}是null
     */
    public void execute(Runnable command) {
        if (command == null) // 非空判断
            throw new NullPointerException();
        /*
         * 分3步进行:
         *
         * 1. 如果运行的线程少于corePoolSize,请尝试使用给定命令作为其第一
         * 个任务启动新线程。对addWorker的调用以原子方式检查 runState 和
         * workerCount,因此通过返回false来防止在不应该添加线程时添加线程
         * 的错误警报.
         *
         * 2. 如果一个任务可以成功地排队,那么我们仍然需要仔细检查是否应该添
         * 加一个线程(因为自上次检查以来存在已有的线程已死亡),或者自进入此
         * 方法后池是否已关闭。因此,我们重新检查状态,如果停止,则在必要时回
         * 滚排队,如果没有,则启动新线程.
         *
         * 3. 若我们无法将任务排队,那个么我们将尝试添加一个新线程。如果失败,
         * 我们知道我们已关闭或饱和,因此拒绝该任务.
         */
        int c = ctl.get(); // 获取 ctl 属性
        // 工作线程的个数是否小于核心线程数
        if (workerCountOf(c) < corePoolSize) {
            // 通过 addWorker 添加一个核心线程去执行 command 任务
            if (addWorker(command, true))
                // 添加核心线程成功返回true,直接return
                return;
            // 添加核心线程失败,重新获取 ctl 属性
            c = ctl.get();
        }
        
        // 这里往下是创建核心线程失败的情况
        // 通过 isRunning 判断当前线程池状态是否是RUNNING
        // 如果是RUNNING,将执行offer将任务添加到工作队列(成功返回true,失败返回false)
        if (isRunning(c) && workQueue.offer(command)) {
            // 任务添加到工作队列成功,重新获取 ctl 属性
            int recheck = ctl.get();
            // 判断当前线程池状态时都是非RUNNING(>=SHUTDOWN),尝试从工作队列移除任务
            if (! isRunning(recheck) && remove(command))
            	// 线程池状态不正确,执行拒绝策略
                reject(command);
            // 状态是RUNNING或者工作队列移除任务失败,判断工作线程是否为0
            else if (workerCountOf(recheck) == 0)
				// 如果是0说明刚扔进去的任务(移除还失败了),但是没有工作线程执行这个任务
                // 添加一个空任务非核心线程,为了处理工作队列中排队的任务
                addWorker(null, false);
        }
        // 当前不是RUNNING状态或者任务添加到工作队列失败,尝试添加非核心线程执行当前任务
        else if (!addWorker(command, false))
            // 创建非核心线程失败执行拒绝策略
            reject(command);
    }
    
    private static boolean isRunning(int c) {
        return c < SHUTDOWN;
    }
}

6、addWorker

添加工作线程并启动工作线程

public class ThreadPoolExecutor extends AbstractExecutorService {

    /* 锁. */
    private final ReentrantLock mainLock = new ReentrantLock();

    /**
     * 包含池中所有工作线程的集合。仅在持有mainLock时访问.
     */
    private final HashSet<Worker> workers = new HashSet<Worker>();

    /**
     * 跟踪达到的最大池大小。仅在mainLock下访问.
     */
    private int largestPoolSize;

    /**
     * 添加工作线程。
     *
     * 检查是否可以根据当前池状态和给定绑定(核心或最大值)添加新工作线程。
     * 如果是,将相应地调整工作人员计数,如果可能,将创建并启动一个新的
     * 工作人员,并将firstTask作为其第一个任务运行。如果池已停止或符合
     * 关闭条件,则此方法返回false。如果线程工厂在被请求时未能创建线程,
     * 它也会返回false。如果线程创建失败,无论是由于线程工厂返回null,
     * 还是由于异常(通常是 Thread.start() 时的 OutOfMemoryError),
     * 我们都会完全回滚.
     *
     * 入参:firstTask 新线程应首先运行的任务(如果没有,则为空)。
     *				  工作线程是用初始的第一个任务(在方法execute()中)
     *				  创建的,以在少于corePoolSize线程(在这种情况下,
     *				  我们总是启动一个)或队列已满(在这种情形下,我们必
     *				  须绕过队列)时绕过队列。最初,空闲线程通常是通过
     *				  prestartCoreThread创建的,或者用来替换其他正
     *				  在死亡的工作线程.
     *
     * 入参:core 如果为true,则使用corePoolSize作为绑定,否则使用
     			maximumPoolSize。(此处使用布尔指示符,而不是值,
     * 			以确保在检查其他池状态后读取新值。)
     *
     * 返回:true 如果成功
     */
    private boolean addWorker(Runnable firstTask, boolean core) {
        // ⑴ 对线程池状态的判断,以及对工作线程数量的判断
        // 外层for循环标识
        retry:
        for (;;) {
            // 获取 ctl 的值
            int c = ctl.get();
            // 拿到线程池的状态
            int rs = runStateOf(c);

            // 如果状态非RUNNING,继续后续判断,验证当前任务是否需要被处理
            if (rs >= SHUTDOWN &&
                //!( 状态SHUTDOWN,任务=null,工作队列非空;这里映射execute.addWorker(null, false))
                ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()))
                // 线程池不是RUNNING状态,不接收新任务
                // 不符合execute.addWorker(null, false),不走当前位置
                return false;

            // 外层for判断状态↑↑↑,内层for判断数量↓↓↓
            for (;;) {
                // 基于ctl获取当前工作线程数
                int wc = workerCountOf(c);
                // 如果工作线程数>=最大值
                if (wc >= CAPACITY ||
                    // 核心是否达到最大核心数,非核心是否达到最大线程数
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    // 工作线程已经达到最大值了不能再创新新线程了直接返回false
                    return false;
                // 以CAS的方式,对工作线程数+1,如果成功直接跳出外层for循环
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                // 重新获取 ctl (走到这里说明当前工作线程数+1失败了,就是并发竞争一个成功其余失败了)
                c = ctl.get();
                // 基于新ctl获取线程池状态判断其是否和之前的rs状态一致
                if (runStateOf(c) != rs)
                    // 不一致说明并发操作导致线程池状态发生了变化,需要跳回外层for循环重新判断状态
                    continue retry;
                // 否则,由于workerCount更改,CAS失败;重试内部循环
            }
        }

		// ⑵ 添加工作线程并启动工作线程
        boolean workerStarted = false; // 启动标识
        boolean workerAdded = false; // 添加标识
        Worker w = null; // worker对象,就是工作线程
        try {
            // 创建工作线程,并把任务扔进Worker
            w = new Worker(firstTask);
            // 拿到 Worker 中绑定的 Thread 线程
            final Thread t = w.thread;
            // 肯定不为null!!!why?刚特么new的你说它怎么null?!!!(健壮性判断)
            if (t != null) {
                // 获取this的锁
                final ReentrantLock mainLock = this.mainLock;
                // 加锁,防止并发冲突
                mainLock.lock();
                try {
                    // 基于新获取的 ctl 拿到线程池状态
                    int rs = runStateOf(ctl.get());
                    // 线程池状态是RUNNING
                    if (rs < SHUTDOWN ||
                        // 线程池状态是SHUTDOWN且任务为null,映射execute.addWorker(null, false)
                        (rs == SHUTDOWN && firstTask == null)) {
                        // 开始添加工作线程的步骤
                        // 判断t是否已经处于run状态(健壮性判断)
                        if (t.isAlive())
                            throw new IllegalThreadStateException();
                        // 将构建好的Worker对象添加到workers
                        workers.add(w);
                        // 获取工作线程个数
                        int s = workers.size();
                        // 记录历史最大工作线程数
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        // 将工作线程添加标识设置为true
                        workerAdded = true;
                    }
                } finally {
                    // 释放锁
                    mainLock.unlock();
                }
                // 如果工作线程添加成功
                if (workerAdded) {
                    // 启动工作线程(干活吧你!)
                    t.start();
                    // 将工作线程添加标识设置为true
                    workerStarted = true;
                }
            }
        } finally {
            // 如果作线程添加失败
            if (! workerStarted)
                // 
                addWorkerFailed(w);
        }
        return workerStarted;
    }

    /**
     * 回滚工作线程创建.
     * - 从workers中移除worker(如果存在)
     * - 递减worker计数
     * - 重新检查终止,以防该worker的存在阻碍终止
     */
    private void addWorkerFailed(Worker w) {
        // 加锁
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 如果worker存在
            if (w != null)
                // 从workers中移除worker
                workers.remove(w);
            // 将工作线程数-1(映射+1:compareAndIncrementWorkerCount(c))
            decrementWorkerCount();
            // 尝试将线程池状态变成TIDYING
            tryTerminate();
        } finally {
            // 释放锁
            mainLock.unlock();
        }
    }
}

7、Worker

public class ThreadPoolExecutor extends AbstractExecutorService {

    /**
     * Class Worker主要维护运行任务的线程的中断控制状态,以及其他次要的簿记。
     * 此类机会性地扩展了AbstractQueuedSynchronizer,以简化获取和释放围绕
     * 每个任务执行的锁。这可以防止旨在唤醒等待任务的工作线程而不是中断正在运行
     * 的任务的中断。我们实现了一个简单的非可重入互斥锁,而不是使用重入锁,因为
     * 我们不希望工作任务在调用setCorePoolSize等池控制方法时能够重新获取锁。
     * 此外,为了抑制中断直到线程实际开始运行任务,我们将锁状态初始化为负值,并
     * 在启动时将其清除(在runWorker中).
     */
    private final class Worker
        extends AbstractQueuedSynchronizer // 线程中断
        implements Runnable
    {
        
        /** 工作线程的Thread对象,并且是在初始化时构建的. */
        final Thread thread;
        /** 需要执行的任务. */
        Runnable firstTask;
        /** Per-thread task counter */
        volatile long completedTasks;

        // 构造
        Worker(Runnable firstTask) {
            // AQS初始化,state=-1,刚刚初始化的线程是不能被中断的
            setState(-1);
            // 实例化的时候初始化任务
            this.firstTask = firstTask;
            // 通过线程工程给Worker构建Thread对象
            this.thread = getThreadFactory().newThread(this);
        }

        /** t.start() */
        public void run() {
            runWorker(this);
        }

        // Lock methods
        //
        // 值0表示解锁状态.
        // 值1表示锁定状态.
        // (注:中断线程不是让线程立即停止,只是将thread的中断标识置为true)

        protected boolean isHeldExclusively() {
            return getState() != 0;
        }

        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        // 将 state 置为0,在 runworker中,为了表示当前线程允许被中断
        protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        public void lock()        { acquire(1); }
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }

        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }
}

8、runWorker

执行任务的流程,并作了中断线程相关的 lock操作

public class ThreadPoolExecutor extends AbstractExecutorService {

    /**
     * 主工作程序运行循环。重复从队列中获取任务并执行它们,同时处理许多问题:
     *
     * 1. 我们可以从初始任务开始,在这种情况下,我们不需要获得第一个任务。否则,
     * 只要池在运行,我们就从getTask获取任务。如果返回null,则工作进程将由于池
     * 状态或配置参数的更改而退出。其他退出是由外部代码中的异常抛出导致的,在这种
     * 情况下,completedAbruptly 成立,这通常会导致processWorkerExit替换
     * 此线程。
     *
     * 2. 在运行任何任务之前,获取锁以防止任务执行时其他池中断,然后我们确保除非
     * 池停止,否则该线程不会设置其中断。
     *
     * 3. 每个任务运行之前都会调用beforeExecute,这可能会引发异常,在这种情况
     * 下,我们会导致线程在不处理任务的情况下死亡(CompletedThrough=true时
     * 中断循环)
     *
     * 4. 假设beforeExecute正常完成,我们运行任务,收集任何抛出的异常以发送给
     * afterExecute。我们分别处理RuntimeException、Error(这两个规范都保证
     * 我们可以捕获)和任意抛出。因为我们不能在Runnable中重新播放垃圾。运行时,
     * 我们将它们包装在输出的错误中(到线程的UncaughtExceptionHandler)。任
     * 何抛出的异常也会保守地导致线程死亡。
     *
     * 5. 任务完成后。运行完成后,我们调用afterExecute,这也可能引发异常,这也会
     * 导致线程死亡。根据JLS第14.20节的规定,即使task.run()抛出异常,此异常也是
     * 有效的。
     *
     * 异常机制的净效果是,afterExecute和线程的UncaughtExceptionHandler
     * 具有尽可能准确的信息,可以提供用户代码遇到的任何问题。
     *
     * @param w the worker
     */
    final void runWorker(Worker w) {
        // 拿到当前工作线程
        Thread wt = Thread.currentThread();
        // 拿到Worker对象中封装的任务
        Runnable task = w.firstTask;
        // 将Worker对象中firstTask归位
        w.firstTask = null;
        // worker.unlock()
        w.unlock(); // 允许中断
        // 任务执行时,钩子函数中是否抛出异常的标识!!!默认true
        boolean completedAbruptly = true;
        try {
            // ⑴ 任务不为null(执行execute、submit时传入的任务)
            while (task != null || 
                   // ⑵ 从工作队列获取任务不为null(从工作队列拿任务执行)
                   (task = getTask()) != null) {
                // work.lock() :在SHUTDOWN状态下当前线程不允许被中断
                // 非可重入锁,因此在中断时,也需要对worker进行lock,不能获取就代表当前工作线程正在执行任务
                w.lock();
                // 如果线程池状态是STOP,必须将当前线程终端
                // 第一个判断:当前线程池状态是否>STOP
                // 第二个判断:判断中断标记位并归位
                // (false说明不是STOP,true则需要再次查看是否是并发操作导致线程池状态为STOP)
                if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&
                    // 查询当前线程中断标记是否为false
                    !wt.isInterrupted())
                    // 将中断标记设置为true
                    wt.interrupt();
                try {
                    // 钩子函数:前置增强(空方法,留作扩展)
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run(); // 开启线程执行任务~
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        // 钩子函数:后置增强(空方法,留作扩展)
                        afterExecute(task, thrown);
                    }
                } finally {
                    // 将task置null
                    task = null;
                    // 执行任务成功的个数+1
                    w.completedTasks++;
                    // worker.unlock() : 将state设置为0
                    w.unlock();
                }
            }
            // 任务执行时,钩子函数中未抛出异常此标识置false
            completedAbruptly = false;
        } finally {
            // 收尾工作
            processWorkerExit(w, completedAbruptly);
        }
    }
}

9、getTask

从工作队列 workQueue获取任务

public class ThreadPoolExecutor extends AbstractExecutorService {

    /**
     * 如果为false(默认),则即使在空闲时,核心线程也保持活动状态。
     * 如果为true,则核心线程使用 keepAliveTime 超时等待工作
     */
    private volatile boolean allowCoreThreadTimeOut; // 如果设置true不如使用cacheThread

    /**
     * 根据当前配置设置对任务执行阻塞或定时等待,如果此工作进程由于以下任何原因而必须退出,则返回null:
     * 
     * 1. 存在多于maximumPoolSize个工作线程(由于调用了setMaximumPoolSize)
     * 2. 线程池已经停止
     * 3. 线程池已关闭,队列为空
     * 4. 此工作线程在等待任务时超时,超时工作线程在超时等待之前和之后都会终止(即,
     *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
     *    如果队列为非空,则此工作线程不是池中的最后一个线程。
     *
     * @return task, or null 如果worker必须退出,在这种情况下,workerCount将递减
     */
    private Runnable getTask() {
        // 超时标志(超时后非核心线程要被干掉):上次 poll() 超时了吗?
        boolean timedOut = false;

        for (;;) {
            //========================1、判断线程池状态=====================
            // 获取ctl
            int c = ctl.get();
            // 获取线程池状态
            int rs = runStateOf(c);

            // 仅在必要时检查队列是否为空(状态>=SHUTDOWN && <STOP)
            // 干掉当前worker条件:
            // ⑴ 线程池状态 >= STOP (STOP:不接收新任务,中断工作线程,不处理队列任务)
            // ⑵ rs >= SHUTDOWN && workQueue.isEmpty() (SHUTDOWN:不接收新任务,可处理队列任务)
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                // 工作线程个数-1
                decrementWorkerCount();
                // 返回null,在后续processWorkerExit方法干掉当前worker
                return null;
            }

            //========================2、判断工作线程数量=====================
            // 获取当前工作线程数量
            int wc = workerCountOf(c);

            // workers 是否会被淘汰? 允许超时或者大于核心线程数(是否是核心线程只看数量不看线程)
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            // 是否超过最大线程数 || workers可淘汰且超时
            if ((wc > maximumPoolSize || (timed && timedOut))
                // 满足上面条件后,工作线程数量 > 1 或工作队列为空,就干掉当前worker
                && (wc > 1 || workQueue.isEmpty())) {
                // 通过CAS方式移除当前线程
                if (compareAndDecrementWorkerCount(c))
                    // 返回null,在后续processWorkerExit方法干掉当前worker
                    return null;
                continue; // 如果多线程必定只有一个成功,其他线程继续循环重新尝试干掉他们各自的worker
            }


            //=======================3、尝试从工作队列拿任务=====================
            try {
                Runnable r = timed ?
                    // (非核心线程)阻塞一定时间从工作线程拿任务,如果超时非核心线程就要被干掉了
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                	// (核心线程)一直阻塞,一直等着拿任务继续干活
                    workQueue.take();
                if (r != null)
                    return r; // 拿到任务返回上一级方法开启线程干活
                // 非核心线程超时了也没拿到任务,超时标志置true,继续循环尝试返回null干掉当前worker
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false; // workQueue.take()抛出的异常,继续循环尝试重新获取任务
            }
        }
    }
}

10、processWorkerExit

public class ThreadPoolExecutor extends AbstractExecutorService {

    /**
     * 已完成任务的计数器。仅在终止worker线程时更新。仅在主锁下访问。
     */
    private long completedTaskCount;

    /**
     * 为垂死的worker执行清理和记账。
     * 仅从工作线程调用。除非设置了CompletedStrutly,否则假设workerCount已被调整以考虑退出。
     * 此方法从工作线程集中删除线程,如果由于用户任务异常而退出,或者如果运行的工作线程少于
     * corePoolSize,或者队列非空但没有工作线程,则可能终止池或替换工作线程。
     *
     * @param w the worker
     * @param completedAbruptly 如果工作人员因用户异常而死亡
     */
    private void processWorkerExit(Worker w, boolean completedAbruptly) {
        // 如果执行此方法不是getTask返回null导致的,而是直接由于异常导致的(一般是那俩增强钩子函数抛的)
        if (completedAbruptly) // 如果是突然的,则workerCount没有调整
            decrementWorkerCount(); // 手动工作线程数-1

        // 加锁!
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 将当前worker执行任务的总数汇总到计数器
            completedTaskCount += w.completedTasks;
            // 干掉当前worker
            workers.remove(w);
        } finally {
            // 释放锁
            mainLock.unlock();
        }

        // 尝试将线程池状态变成TIDYING
        tryTerminate();

        // 获取ctl
        int c = ctl.get();
        
        // 如果线程池状态<STOP:RUNNING或SHUTDOWN
        // (只有<STOP才往下判断,因为STOP就不处理工作队列的任务了,就算当前正在执行的任务也要尝试中断)
        if (runStateLessThan(c, STOP)) {
            // 如果是正常状态移除当前worker
            if (!completedAbruptly) {
                // 获取可存活的核心线程数
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                // 如果min为0 并且 工作队列不为空
                if (min == 0 && ! workQueue.isEmpty())
                    // min设置为1
                    min = 1;
                // 如果当前工作线程数 >= min:有worker在干活且数量不少于min
                if (workerCountOf(c) >= min)
                    return; // 直接return,当前worker删了就删了,无所谓
            }
            // 走到这里说明是非正常状态移除了worker 或者 当前工作线程数 < min
            // 再添加一个工作线程做任务干活
            addWorker(null, false);
        }
    }

    /**
     * 如果(SHUTDOWN and pool and queue empty)或(STOP and pool empty)过渡到 TERMINATED 状态
     * 如果符合终止条件,但workerCount为非零,则中断空闲工作进程以确保关机信号传播。
     * 必须在任何可能导致终止的操作之后调用此方法——减少worker数量或在关闭期间从队列中删除任务。
     * 该方法是非私有的,允许从ScheduledThreadPoolExecutor进行访问。
     */
    final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            if (workerCountOf(c) != 0) { // Eligible to terminate
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ThreadPoolExecutorJava 中用于管理线程池的类,它实现了 ExecutorService 接口。它可以帮助我们更方便地管理和调度多线程任务的执行。 下面是 ThreadPoolExecutor 的原理概述: 1. 构造函数:ThreadPoolExecutor 的构造函数接收一些参数,包括核心线程数、最大线程数、任务队列、线程工厂、拒绝策略等。通过这些参数,我们可以配置线程池的大小和行为。 2. 核心线程池ThreadPoolExecutor 会首先创建核心线程池核心线程池中的线程数量不会超过核心线程数的设定,即使线程处于空闲状态也不会被回收。 3. 任务队列:当提交一个任务时,如果核心线程池已满,任务会被放入任务队列中等待执行。ThreadPoolExecutor 提供了多种类型的任务队列,如无界队列和有界队列等,可以根据需求进行选择。 4. 最大线程数控制:当任务队列已满时,ThreadPoolExecutor 会根据最大线程数的设定来创建新的线程,直到达到最大线程数。超过最大线程数的任务将会根据指定的拒绝策略进行处理。 5. 执行任务:当有任务可执行时,ThreadPoolExecutor 会从任务队列中取出任务,并将其交给一个空闲的线程执行。如果核心线程池中的线程都在执行任务,新的任务会被放入任务队列中等待。 6. 拒绝策略:当任务队列已满且达到最大线程数时,ThreadPoolExecutor 会根据指定的拒绝策略来处理无法执行的任务。常见的拒绝策略有抛出异常、丢弃任务等。 以上是 ThreadPoolExecutor 的基本原理概述。详细的源码实现可以参考 Java SDK 的源码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纯纯的小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值