JDK源码那些事儿之ThreadPoolExecutor

前面的文章中分析了Thread的源码,并介绍了其基本应用,然而在实际的企业级应用中执行任务的线程很少直接通过创建Thread,实现run方法的方式完成,通常是通过线程池的方式提交任务来更好的利用资源,进一步简化线程的使用,并防止线程资源的滥用。今天我们就一起来学习下ThreadPoolExecutor的源码,看一看jdK中线程池是如何创建和使用的

前言

JDK版本号:1.8.0_171

如果使用线程,我们通常都是使用线程池来进行操作,你可曾想过为什么?无非是效率,性能和资源多方面的考虑,笔者就不进行总结了,大家可以多思考下

在使用线程池时,我们通常都是通过Executors的工厂方法来得到的,当然,这些工厂方法最终基本上又是调用的ThreadPoolExecutor的构造器,可参考Executors的源码部分。不过阿里的java规范中也指出直接使用Executors方式可能会出现问题,还是直接通过ThreadPoolExecutor创建需要的线程池较好,之前在进行阻塞队列的源码学习时我也曾提到过线程池的使用,今天我们就看一看ThreadPoolExecutor的源码,学习下jdk中的线程池的实现原理

类定义

public class ThreadPoolExecutor extends AbstractExecutorService

关系图

Executor

我们先来看下Executor接口,我们可以看到,其中只定义了一个方法,入参为Runnable类,注释上也说明了这个类存在的意义,执行提交的Runnable任务的对象,在未来某个时间执行给定的命令。该命令可能在新的线程、已入池的线程或者正调用的线程中执行。这样在具体的实现中可以对Runnable任务提交与执行进行了解耦操作,我们只需要提交实现的Runnable任务即可,具体执行的部分交由Executor实现类完成,不需要关注其内部是如何实现的

public interface Executor {

    void execute(Runnable command);
}

当然,注释部分也清楚的说明了同步还是异步(使用线程)执行由具体的Executor实现类决定。其中ExecutorService接口进一步进行了扩展,提供了Executor的管理相关方法(关闭Executor)和异步任务跟踪(Future),在AbstractExecutorService抽象类中实现了默认通用的方法,我们能看到submit方法提交的Runnable任务被封装成了FutureTask,以便完成任务的跟踪,具体不再多说,有兴趣可以自行研究

常量/变量

    // control state,线程池控制状态标识,表示线程池的运行状态以及当前活动的线程,可参考后面的讲解
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    // int值占32位,其中3位表示线程池运行状态,剩余部分表示活动的线程数,这里就表示其占用的位数
    private static final int COUNT_BITS = Integer.SIZE - 3;
    // 线程数最大值,最大能表示的数值
    // 即二进制数值0001 1111 1111 1111 1111 1111 1111 1111
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // runState is stored in the high-order bits
    // 线程池运行状态
    // 我们可以看到其左移的位数为COUNT_BITS
    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;
    
    // 任务阻塞队列
    private final BlockingQueue<Runnable> workQueue;
    // 可重入锁
    private final ReentrantLock mainLock = new ReentrantLock();
    // 保存工作线程的集合,访问前必须获得mainLock锁
    private final HashSet<Worker> workers = new HashSet<Worker>();
    // 等待中断条件
    private final Condition termination = mainLock.newCondition();
    // 最大活动线程数
    private int largestPoolSize;
    // 任务完成总数
    private long completedTaskCount;

    // 线程工厂
    private volatile ThreadFactory threadFactory;
    // 拒绝策略
    private volatile RejectedExecutionHandler handler;
    // 空闲线程存活时间
    private volatile long keepAliveTime;
    // 是否允许核心线程超时
    // 为true时使用keepAliveTime作为超时等待时间
    // 为false时所有核心线程(包含空闲的)一直保持存活
    private volatile boolean allowCoreThreadTimeOut;
    // 核心线程数
    // 当设置allowCoreThreadTimeOut为true时核心线程数最小为0
    // 1.当任务提交时线程池中活动线程数还未达到设定的核心线程数,则直接创建核心线程执行提交的任务
    // 2.当任务提交时线程池中活动线程数已达到设定的核心线程数,但还未达到最大线程数,则放入队列中进行等待处理或者队列满了之后直接创建线程处理
    // 3.当任务提交时线程池中活动线程数已达到设定的最大线程数,则直接执行拒绝策略
    private volatile int corePoolSize;
    // 最大线程数,小于等于CAPACITY
    private volatile int maximumPoolSize;
    // 默认的拒绝策略,对拒绝的任务直接抛出异常
    private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();
    // 安全控制访问,简单了解就好,不是重点
    private static final RuntimePermission shutdownPerm =
        new RuntimePermission("modifyThread");
    private final AccessControlContext acc;     

这里对其中的ctl进行说明,初始化时值为:

(-1 << COUNT_BITS) | 0 = 1110 0000 0000 0000 0000 0000 0000 0000

此时前3位表示线程池处于RUNNING状态,后面29位表示线程池中当前活动的线程数为0,其他状态可参考下表理解

状态 二进制数值
RUNNING 1110 0000 0000 0000 0000 0000 0000 0000
SHUTDOWN 0000 0000 0000 0000 0000 0000 0000 0000
STOP 0010 0000 0000 0000 0000 0000 0000 0000
TIDYING 0100 0000 0000 0000 0000 0000 0000 0000
TERMINATED 0110 0000 0000 0000 0000 0000 0000 0000

同时线程池中的每种状态在注释部分也进行了解释,每种状态下对应的是什么状况还是需要稍微了解的,可参考下表理解:

状态 说明
RUNNING 接收新的任务并且处理已经提交到队列中的任务
SHUTDOWN 不接收新的任务但是处理已经提交到队列中的任务
STOP 不接收新的任务,也不处理已经提交到队列中的任务,同时中断已经在运行的任务
TIDYING 终止所有任务,活动线程数workerCount被设置为0,触发线程的terminated方法执行
TERMINATED terminated方法执行完毕

状态变化同样进行了说明,可参考下图了解:


状态变化

构造方法

在重载的方法可以看到可以使用默认的线程工厂和默认的拒绝策略,最终都是调用下面这个方法

    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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        // 转换成纳秒单位
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

内部类

接下来看下其内部类的实现,主要是Worker和拒绝策略

Worker

Worker继承了AQS,实现了Runnable接口,Worker是线程池中用于执行任务的线程。关于AQS的大名大家应该或多或少的有所了解,之后我也会分析其源码实现,这里大概理解即可,AQS定义了一套多线程访问共享资源的同步器框架,也就是解决多线程下对共享资源访问的相关问题,我们只要按照这个框架来实现使用即可,这里在线程池中很明显符合这种场景

    private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        private static final long serialVersionUID = 6138294804551838833L;

        // 线程
        final Thread thread;
        // 线程需要执行的任务
        Runnable firstTask;
        // 当前线程已经完成的任务数
        volatile long completedTasks;

        Worker(Runnable firstTask) {
            // AQS状态设置为-1
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        public void run() {
            // run方法执行任务,将当前的work传递过去
            runWorker(this);
        }

        // 是否锁定
        //
        // 0代表未锁定状态
        // 1代表锁定状态
        protected boolean isHeldExclusively() {
            return getState() != 0;
        }
        
        // 实现AQS的抽象方法,CAS尝试获取锁,将state状态置为1,成功则返回true,失败则返回false
        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
        // 尝试释放锁,将state状态置为0
        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) {
                }
            }
        }
    }

从上面我们可以看到最终是通过Worker中的线程执行其run方法中runWorker来完成任务的执行的,而runWorker是ThreadPoolExecutor的方法,将worker本身进行了传递,放到ThreadPoolExecutor.runWorker中进行处理

AbortPolicy

默认的拒绝策略实现,可以看到实现的接口方法rejectedExecution的说明,主要是对不能再接受任务时进行的相关处理,即线程池队列已满时对后续任务的处理。这个默认的处理我们也可以看到队列满了之后直接抛出RejectedExecutionException异常

    public static class AbortPolicy implements RejectedExecutionHandler {

        public AbortPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

CallerRunsPolicy

CallerRunsPolicy策略,在任务被拒绝添加后,会调用当前线程池的所在的线程去执行被拒绝的任务,当然这种情况下有可能会造成主线程的阻塞,慎用

    public static class CallerRunsPolicy implements RejectedExecutionHandler {

        public CallerRunsPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            // 会判断线程池状态是否正常
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

DiscardPolicy

DiscardPolicy策略,会让被线程池拒绝的任务直接抛弃,不会抛异常也不会执行,从下面源码部分可以看出直接为空操作,什么也不做

    public static class DiscardPolicy implements RejectedExecutionHandler {
    
        public DiscardPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

DiscardOldestPolicy

DiscardOldestPolicy策略,当任务被拒绝添加时,会抛弃任务队列中最老的任务也就是最先加入队列的,再把这个新任务添加进去

    public static class DiscardOldestPolicy implements RejectedExecutionHandler {

        public DiscardOldestPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                // 出队最老的任务
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

重要方法

runStateOf/workerCountOf/ctlOf

3个方法主要是用来计算线程池状态和活动线程数以及更新ctl的位运算操作,可参考上面的ctl的说明进行理解

    // 当前线程池运行状态,取最高的3位作为运行状态
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    // 当前的活动线程数,取低29位作为活动线程数
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    // 生成ctl计算,也就是上面两个方法的或操作
    private static int ctlOf(int rs, int wc) { return rs | wc; }

tryTerminate

尝试终止线程池,参考上面的线程池状态转换图,执行此方法前线程池状态处于SHUTDOWN或者STOP状态,可以参考其调用地方的源码,以下两种情况才能成功终止线程池,即对应上面的状态转换图

  • 线程池为空,任务队列为空且处于SHUTDOWN状态
  • 线程池为空且处于STOP状态

处于上述情况则线程池先转变为TIDYING,再转变为TERMINATED,与线程池状态转换图一致,参考理解

    final void tryTerminate() {
        // 循环自旋
        for (;;) {
            int c = ctl.get();
            // 线程池处于RUNNING状态
            // 或者TIDYING,TERMINATED状态(此时说明其他线程在执行tryTerminate)
            // 或者SHUTDOWN状态且任务队列不为空时(还有未完成任务需要执行)
            // 直接退出
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            // 活跃线程数非0,中断其中一个空闲线程worker
            if (workerCountOf(c) != 0) { // Eligible to terminate
                interruptIdleWorkers(ONLY_ONE);
                return;
            }
            
            // 先获取锁
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // 将ctl状态置为TIDYING,且活动线程数置为0
                // 这种状态下执行执行terminated,默认是空方法,子类可以进行重写
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                        // 最终将ctl状态置为TERMINATED
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

execute

执行提交的任务,提交任务submit方法最终也是调用的该方法进行任务的执行的。此方法会在活动线程数超过核心线程数corePoolSize时将任务放在任务队列中等待空闲线程拿到任务去执行

    public void execute(Runnable command) {
        // 任务非空
        if (command == null)
            throw new NullPointerException();
            
        int c = ctl.get();
        // 活动线程数小于核心线程数
        if (workerCountOf(c) < corePoolSize) {
            // 添加新的线程执行任务
            // 参数为true表示活动线程数不能超过核心线程数
            if (addWorker(command, true))
                return;
            // 再次获取ctl
            c = ctl.get();
        }
        // 执行到这里表示活动的线程数大于等于核心线程数
        // 上面添加worker未成功
        // 线程池处于运行状态,则将任务尝试放入任务队列等待
        if (isRunning(c) && workQueue.offer(command)) {
            // 再次获取ctl
            int recheck = ctl.get();
            // 如果线程池不在RUNNING状态,则需要将任务从队列中移除
            // 同时执行拒绝策略拒绝任务
            if (! isRunning(recheck) && remove(command))
                reject(command);
            // 执行到此处分支判断活动线程数为0
            // 添加新的空任务worker,唤醒等待中的队列任务去执行   
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        // 执行到这个分支表示线程池状态非RUNNING状态或者任务队列已满
        // 尝试添加worker
        else if (!addWorker(command, false))
            // 未添加成功则执行拒绝策略
            reject(command);
    }

addWorker

addWorker创建新的线程worker执行任务,core为true时表示不能超过核心线程数,false则表示不能超过最大线程数

当满足下列任一情况时,不再添加线程任务,即返回false,添加任务失败:

  • 当前线程池处于STOP,TIDYING,TERMINATED状态时
  • 当前线程池处于SHUTDOWN状态时,任务非空
  • 当前线程池处于SHUTDOWN状态时,任务为空,任务队列为空

这里是因为线程池状态为SHUTDOWN时,不再允许添加新的任务,但是会执行已在任务队列中的任务,具体可参考runWorker方法,addWorker创建完新的worker后会启动线程,如果任务为空则会从任务队列中获取任务来执行

    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            // 获取ctl
            int c = ctl.get();
            // 当前线程池的运行状态
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            // 参考上面的说明
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;
            
            for (;;) {
                // 当前活动线程数量
                int wc = workerCountOf(c);
                // 线程数大于等于规定的线程数就不再继续执行
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                // CAS更新ctl
                if (compareAndIncrementWorkerCount(c))
                    // 成功直接跳出循环
                    break retry;
                // 失败则重新获取ctl
                c = ctl.get();  // Re-read ctl
                // 验证运行状态,与之前不同则重新跳出继续循环,否则在这个内部继续循环
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
        
        // 到此,表明已经成功更新ctl值加1,下面是添加构造的Worker的部分了
        // worker增加是否启动标识
        boolean workerStarted = false;
        // worker增加是否成功标识
        boolean workerAdded = false;
        Worker w = null;
        try {
            // 创建新的Worker
            w = new Worker(firstTask);
            // Worker中对应的线程
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    int rs = runStateOf(ctl.get());
                    
                    // 线程池为RUNNING状态
                    // 或者线程池为SHUTDOWN状态并且任务为空
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        // worker中的线程被启动则抛出异常
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        // 添加worker
                        workers.add(w);
                        // 获取当前workers的数量
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    // 启动worker线程
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                // 任务启动失败,删除回滚
                addWorkerFailed(w);
        }
        return workerStarted;
    }

getTask

从队列中获取任务,在获取任务前需要先进行一些处理

    private Runnable getTask() {
        // 记录上次从队列取任务超时的标识
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            // 线程池状态为STOP,TIDYING,TERMINATED
            // 或者线程池状态为SHUTDOWN且任务队列为空
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                // 活跃线程数递减
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            // 当线程池设置超时等待获取任务或者活跃线程数大于核心线程数
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            // 活跃线程数大于最大线程数并且活跃线程数大于1或任务队列为空
            // 超时并且活跃线程数大于1或任务队列为空
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                // 递减活跃线程数
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
            
            // 从任务队列获取任务
            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

runWorker

执行任务核心方法,先执行提交的worker中的任务firstTask,如果firstTask为null则会去任务队列中获取任务来执行,且当任务执行后,会再去队列中取任务来执行

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        // 将worker中的firstTask置为null
        w.firstTask = null;
        // 允许被中断
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            // 任务非空
            while (task != null || (task = getTask()) != null) {
                // 加锁
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                // 未中断状态下如果处于下列情况下:
                // 线程池为STOP,TIDYING,TERMINATED
                // 或线程池为STOP,TIDYING,TERMINATED且当前线程已中断
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    // 中断线程
                    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 {
                        // 和beforeExecute同样作用
                        afterExecute(task, thrown);
                    }
                } finally {
                    // 执行完毕后将任务置null,方便后续任务队列中任务的执行
                    task = null;
                    // 完成任务数递增
                    w.completedTasks++;
                    w.unlock();
                }
            }
            // 所有任务执行完毕设置标志
            completedAbruptly = false;
        } finally {
            // 后续处理
            processWorkerExit(w, completedAbruptly);
        }
    }

processWorkerExit

runWorker中被调用,最终任务执行完毕或者被中断时退出前进行必要的后续处理,比如更新完成的任务数量,在核心线程数较小时开启新的线程来处理任务队列中的任务

    private void processWorkerExit(Worker w, boolean completedAbruptly) {
        // 工作线程被中断时处理,活动线程递减
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 完成任务的数量
            completedTaskCount += w.completedTasks;
            // 从workers集合中移除入参的worker
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }
        // 尝试终止
        tryTerminate();
        // 获取ctl
        int c = ctl.get();
        // 线程池状态处于RUNNING或SHUTDOWN
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                // 任务正常执行完毕才会进入这里
                // 设置了allowCoreThreadTimeOut则最小值为0否则为corePoolSize
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                //  min为0且任务队列非空,说明还有任务需要继续执行
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                // 活动的线程数大于等于min
                if (workerCountOf(c) >= min)
                    // 不需要创建新的worker继续执行任务了,复用这些已经创建的线程即可
                    return; // replacement not needed
            }
            // 增加新的null任务worker来执行剩余的任务
            addWorker(null, false);
        }
    }

shutdown

参考线程池状态说明,和上面说明的SHUTDOWN状态一样,也就是不再接收新任务,但是还是会处理任务队列中的任务,并且不会中断已在执行中的任务线程

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            // 更新线程池状态为SHUTDOWN
            advanceRunState(SHUTDOWN);
            // 中断空闲worker
            interruptIdleWorkers();
            // shutdown钩子函数,空方法,可被子类实现
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        // 尝试终止线程池
        tryTerminate();
    }

shutdownNow

方法同shutdown类似,不再接收新任务,并且会清除任务队列中的任务,会中断所有任务线程包括已在执行任务的线程

    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            // 更新线程池状态为STOP
            advanceRunState(STOP);
            // 中断worker
            interruptWorkers();
            // 清除队列任务,并将队列任务集合拷贝出来
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        // 尝试终止线程池
        tryTerminate();
        return tasks;
    }

interruptWorkers

中断所有线程workers

    private void interruptWorkers() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers)
                w.interruptIfStarted();
        } finally {
            mainLock.unlock();
        }
    }

interruptIdleWorkers

中断所有空闲线程workers,使用入参onlyOne判断是否只中断一个空闲线程,无入参默认false,中断全部空闲线程workers

    private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
                Thread t = w.thread;
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }
    private void interruptIdleWorkers() {
        interruptIdleWorkers(false);
    }

总结

本文通过ThreadPoolExecutor的源码来介绍了jdk中线程池的实现原理,说明了线程池状态之间的转换,我们可以了解到很多线程池实现的机制,帮助我们在实际的开发中更好的使用,另外,需要注意的是,尽量还是直接使用ThreadPoolExecutor的构造方法来使用线程池而不是使用Executors的工厂方法,其中的弊端可参考阿里的java规范,主要是默认的设置可能会造成一些问题

以上内容如有问题欢迎指出,笔者验证后将及时修正,谢谢

posted @ 2020-02-18 10:43  freeorange  阅读(148)  评论(0编辑  收藏  举报