ThreadPoolExecutor源码分析

1. ThreadPoolExecutor的核心属性

// 当前是线程池的核心属性
// 当前的ctl其实就是一个int类型的数值,内部是基于AtomicInteger套了一层,进行运算时,是原子性的。
// ctl表示着线程池中的2个核心状态:
// 线程池的状态: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;
00000000 00000000 00000000 00000001
00100000 00000000 00000000 00000000
00011111 11111111 11111111 11111111
// 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高三位的值。
private static int runStateOf(int c)     { return c & ~CAPACITY; }
// 基于&运算的特点,保证只会拿到ctl低29位的值。

2. ThreadPoolExecutor有参构造

public ThreadPoolExecutor(int corePoolSize, //核心线程数
                          int maximumPoolSize,  //最大线程数,包含非核心线程和核心线程
                          long keepAliveTime,   //空闲时间,非核心线程在阻塞队列中等待的时间
                          TimeUnit unit,        //非核心工作线程在阻塞队列位置等待时间的单位
                          BlockingQueue<Runnable> workQueue,  // 任务在没有线程处理时,扔到阻塞队列中等待
                          ThreadFactory threadFactory,        // 构建线程的线程工作,可以设置thread的一些信息
                          RejectedExecutionHandler handler) { // 当线程池无法处理投递过来的任务时,执行当前的拒绝策略
      
      // 核心线程数小于0
      // 最大线程数小于等于0(最大线程数必须大于0),
      // 最大线程数小于核心线程数(最大线程数要大于等于核心线程数)
      // 非核心线程的最大空闲时间,可以等于0
      // 以上四个条件满足一个就会报错 IllegalArgumentException
      if (corePoolSize < 0 ||
          maximumPoolSize <= 0 ||
          maximumPoolSize < corePoolSize ||
          keepAliveTime < 0)
        throw new IllegalArgumentException();
      // 阻塞队列等于null,线程工厂等于null,拒绝策略等于null ,就报错 NullPointerException
      // 阻塞队列,线程工厂,拒绝策略都不允许为null,为null就扔空指针异常
      if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
      // 不要关注当前内容,系统资源访问决策,和线程池核心业务关系不大。
      this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
      // 各种赋值,JUC包下,几乎所有涉及到线程挂起的操作,单位都用纳秒。
      // 有参构造的值,都赋值给成员变量。
      // Doug Lea的习惯就是将成员变量作为局部变量单独操作。
      this.corePoolSize = corePoolSize;  
      this.maximumPoolSize = maximumPoolSize;
      this.workQueue = workQueue;
      this.keepAliveTime = unit.toNanos(keepAliveTime);
      this.threadFactory = threadFactory;
      this.handler = handler;
}

3. ThreadPoolExecutor的execute方法

 //command: 用户提交的线程任务
 public void execute(Runnable command) {
        //非空验证,command不能位null
        if (command == null)
            throw new NullPointerException();
        // 获取ctl的值,用于判断
        int c = ctl.get();
        //workerCountOf 获取低29位上的线程个数,
        // 判断ctl中的线程个数是否小于核心线程个数,如果小于返回 true[执行添加核心线程操作]
        if (workerCountOf(c) < corePoolSize) {
            // addWorker(任务,是核心线程吗)
            // addWorker返回true:代表添加工作线程成功
            // addWorker返回false:代表添加工作线程失败
            // addWorker中会基于线程池状态,以及工作线程个数做判断,查看能否添加工作线程
            if (addWorker(command, true))
                return;
                
            //才重新获取一下ctl,说明线程池状态或者是工作线程个数发生了变化,导致添加失败
            c = ctl.get();
        }
        //添加核心线程失败后,执行下面操作
        //判断线程池的状态是否时RUNNING(-1)状态 && 将任务成功添加到队列中
        if (isRunning(c) && workQueue.offer(command)) {
            // 如果任务添加到阻塞队列成功,走if内部
            // 如果任务在扔到阻塞队列之前,线程池状态突然改变了。
            // 重新获取ctl
            int recheck = ctl.get();
            // 重新判断线程池状态,如果不是 -1  && 将任务从阻塞队列移除,
            if (! isRunning(recheck) && remove(command))
                //执行拒绝策略
                reject(command);
            //判断当工作线程数量是否==0
            // 上面刚杠将任务放入阻塞队列中,查看一下工作线程是不是为0
            // 如果工作线程为0,就需要添加一个非核心线程去处理阻塞队列中的任务
            // 发生这种情况有两种:
            1 构建线程池时,核心线程数是0个,
            2:即便有核心线程,可以设置核心线程也允许超时,设置allowCoreThreadTimeOut为true,代表核心线程也可以超时
            else if (workerCountOf(recheck) == 0)
               //添加一个不携带任务的非核心线程,避免阻塞队列中的任务饥饿
                addWorker(null, false);
        }
        // 任务添加队列失败,可能是满了
        // 构建一个非核心线程,如果添加成功就结束,否则进入if 执行 拒绝策略
        else if (!addWorker(command, false))
            reject(command);
    }

4.ThreadPoolExecutor的addWorker方法

    private boolean addWorker(Runnable firstTask, boolean core) {
    //============================校验线程池的状态以及工作线程个数-Start==========================
        // 外层for循环在校验线程池的状态
        // 内层for循环是在校验工作线程的个数
        
        retry: //retry是给外层for循环添加一个标记,是为了方便在内层for循坏跳出外层for循环
        for (;;) {
            //获取ctl
            int c = ctl.get();
            //获取ctl高3位值,线程池的状态
            int rs = runStateOf(c);
            
            // 如果线程池状态是SHUTDOWN,并且此时阻塞队列有任务,工作线程个数为0,添加一个工作线程去处理阻塞队列的任务
            //1. 判断线程池状态是SHUTDOWN,或者>0 的状态
            //2.1  !(线程池状态是SHUTDOWN && firstTask==null && workQueue阻塞队列中不是空的)
            if (rs >= SHUTDOWN &&
                // 如果这三个条件都满足,就代表是要添加非核心工作线程去处理阻塞队列任务
                // 如果三个条件有一个没满足,返回false,配合!,就代表不需要添加
                !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty())
                )
                //不需要添加线程,外面就会执行  reject(command)
                return false;
        //==========================工作线程个数判断
            for (;;) {
                // 基于ctl拿到低29位的值,代表当前工作线程个数
                int wc = workerCountOf(c);
                // 判断工作线程数量是否超过最大值,如果超了就返回 false
                if (wc >= CAPACITY ||
                    // 基于core来判断添加的是否是核心工作线程
                    // 如果是核心:基于corePoolSize去判断
                    // 如果是非核心:基于maximumPoolSize去判断
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                // 没有超,针对ctl进行 + 1,采用CAS的方式
                if (compareAndIncrementWorkerCount(c))
                    // CAS成功后,直接退出外层循环,代表可以执行添加工作线程操作了。
                    break retry;
                c = ctl.get();   // 重新获取一次ctl的值
                // 判断重新获取到的ctl中,表示的线程池状态跟之前的是否有区别
                // 如果状态不一样,说明有变化,重新的去判断线程池状态
                if (runStateOf(c) != rs)
                    continue retry;  // 跳出一次外层for循环
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
    //============================校验线程池的状态以及工作线程个数-END==========================
    
    //============================添加工作线程并且启动工作线程-START==========================
         // 工作线程启动了没,默认false
        boolean workerStarted = false;
        //工作线程添加了么,默认false;
        boolean workerAdded = false;
        //工作线程 默认null
        Worker w = null;
        try {
            //实例化Worker对象,并将 firstTask 传递进去
            w = new Worker(firstTask);
            // 获取Worker 中的Thread对象
            final Thread t = w.thread;
            
            // 判断Thread是否不为null,在new Worker时,内部会通过给予的ThreadFactory去构建Thread交给Worker
            // 判断 t是否为null, // 一般如果为null,代表ThreadFactory有问题。
            if (t != null) {
                // 声明一个锁,保证使用workers成员变量以及对largestPoolSize赋值时,保证线程安全
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();// 加锁操作
                try {
                    // 获取线程池状态

                    int rs = runStateOf(ctl.get());
                    // 判断线程池是否是RUNNING状态,如果是,就执行if代码
                    if (rs < SHUTDOWN ||
                        // 如果线程池状态为SHUTDOWN,并且firstTask为null,添加非核心工作处理阻塞队列任务
                        (rs == SHUTDOWN && firstTask == null)) {
                        // 判断线程是否已经启动,校验ThreadFactory构建线程后,不能自己启动线程,如果启动了,抛出异常
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        
                        //将工作线程Worker对象添加到 成员变量 workers  中  
                        //     private final HashSet<Worker> workers = new HashSet<Worker>();
                        workers.add(w);
                        // 获取workers 数量,拿到工作线程个数
                        int s = workers.size();
                        // largestPoolSize在记录最大线程个数的记录
                        // 如果当前工作线程个数,大于最大线程个数的记录,就赋值
                        if (s > largestPoolSize)
                            largestPoolSize = s; 
                        // 添加工作线程成功
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                // 如果工作线程添加成功了
                if (workerAdded) {
                    t.start(); // 直接启动Worker中的线程
                    workerStarted = true; // 启动工作线程成功
                }
            }
        } finally {
            // 做补偿的操作,如果工作线程启动失败,将这个添加失败的工作线程处理掉
            if (! workerStarted)
                addWorkerFailed(w);
        }
        //  返回工作线程是否启动成功
        return workerStarted;
    }

5. ThreadPoolExecutor的Worker工作线程对象

Worker 对象实现了 Runnable 接口 同时继承了 AbstractQueuedSynchronizer ,
● Worker继承了AQS,目的就是为了控制工作线程的中断。
● Worker实现了Runnable,内部的Thread对象,在执行start时,必然要执行Worker中断额一些操作

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

        /** 线程工厂构建的线程 */
        final Thread thread;
        /** 当前worker要执行的任务,也是用户传递过来的*/
        Runnable firstTask;
        /** 记录着当前线程处理了多少任务 */
        volatile long completedTasks;

        // 构造方法
        Worker(Runnable firstTask) {
            setState(-1); //  // 将State设置为-1,代表当前不允许中断线程
            this.firstTask = firstTask;  // 设置任务
            this.thread = getThreadFactory().newThread(this); // 基于线程工作构建Thread,并且传入的Runnable是Worker
        }

        /** 当thread执行start方法时,调用的就是Worker的run方法 */
        public void run() {
            runWorker(this);// 任务执行时,执行的是ThreadPoolExecutor.runWorker方法
        }
// =======================Worker管理中断================================   
    // 当前方法是中断工作线程时,执行的方法
        void interruptIfStarted() {
            Thread t;
             // 只有Worker中的state >= 0的时候,可以中断工作线程
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                // 如果状态正常,并且线程未中断,这边就中断线程
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
        
        
        protected boolean isHeldExclusively() {
            return getState() != 0;
        }

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

        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(); }

   
    }

6. ThreadPoolExecutor的runWorker方法

runWorker方法就是让Worker拿到任务去执行run方法
并且在内部也处理了在工作线程正常结束和异常结束时的处理方案

   final void runWorker(Worker w) {
        //获取到当前的线程
        Thread wt = Thread.currentThread();
        //从Worker 中的firstTask里拿到 任务
        Runnable task = w.firstTask;
        w.firstTask = null; //  将Worker中的firstTask置位空
        w.unlock(); //worker实现了AQS,将worker中的state状态设置为0,代表着当前线程可以中断
        
        // 判断工作线程是否是异常结束,默认就是异常结束
        boolean completedAbruptly = true;
        try {
            //判断 task 不为空,如果为null,执行|| 后面 ,从getTask中获取任务,同时判断任务不能为null
            while (task != null || (task = getTask()) != null) {
                 // 执行了Worker的lock方法,当前在lock时,shutdown操作不能中断当前线程,因为当前线程正在处理任务
                w.lock();  
                //  比较ctl >= STOP(1),如果满足找个状态,说明线程池已经到了STOP状态甚至已经要凉凉了
                // if(runStateAtLeast(ctl.get(), STOP) && !wt.isInterrupted()) {中断线程}
                
                // 如果线程池状态不是STOP,确保线程不是中断的。
                // 如果发现线程中断标记位是true了,再次查看线程池状态是大于STOP了,再次中断线程
                // 这里其实就是做了一个事情,如果线程池状态 >= STOP,确保线程中断了。
                if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) 
                    &&
                    // 线程池到STOP状态,并且当前线程还没有中断,确保线程是中断的,进到if内部执行中断方法
                    !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 {
                         // 后置勾子函数
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null; // 任务执行完,丢掉任务
                    w.completedTasks++;  // 当前工作线程处理的任务数+1
                    w.unlock();   // 执行unlock方法,此时shutdown方法才可以中断当前线程
                }
            }
            // 如果while循环结束,正常走到这,说明是正常结束
            // 正常结束的话,在getTask中就会做一个额外的处理,将ctl - 1,代表工作线程没一个。
            completedAbruptly = false;
        } finally {
              // 考虑干掉工作线程
            processWorkerExit(w, completedAbruptly);
        }
    }

7. ThreadPoolExecutor的processWorkerExit方法

工作线程在结束前,要执行这个方法

    
    private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // 如果为true,说明Worker工作线程非正常结束
            decrementWorkerCount();  // 将ctl - 1,扣掉一个工作线程
        // 操作Worker,为了线程安全,加锁
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 当前工作线程处理的任务个数累加到线程池处理任务的个数属性中
            completedTaskCount += w.completedTasks;
            workers.remove(w);   // 将工作线程从hashSet中移除
        } finally {
            mainLock.unlock();  // 释放锁
        }
        // 只要工作线程凉了,查看是不是线程池状态改变了。
        tryTerminate();

        int c = ctl.get();
        // 判断线程池状态,当前线程池要么是RUNNING,要么是SHUTDOWN
        if (runStateLessThan(c, STOP)) {
            // 如果线程是正常结束
            if (!completedAbruptly) {
                // 如果核心线程允许超时,min = 0,否则就是核心线程个数
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                // 如果min == 0,可能会出现没有工作线程,并且阻塞队列有任务没有线程处理
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;   // 至少要有一个工作线程处理阻塞队列任务
                  // 如果工作线程个数 大于等于1,不怕没线程处理,正常return
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            // 异常结束,为了避免出现问题,添加一个空任务的非核心线程来填补上刚刚异常结束的工作线程
            addWorker(null, false);
        }
    }

8. ThreadPoolExecutor的getTask方法

工作线程在去阻塞队列获取任务前,要先查看线程池状态
如果状态没问题,去阻塞队列take或者是poll任务
第二个循环时,不但要判断线程池状态,还要判断当前工作线程是否可以被干掉

    // 当前方法就在阻塞队列中获取任务
    // 前面半部分是判断当前工作线程是否可以返回null,结束。
    // 后半部分就是从阻塞队列中拿任务
    private Runnable getTask() {
        boolean timedOut = false; 

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

            // 判断线程池状态是否》=SHUTDOWN(0)
            // 如果线程池状态是STOP,没有必要处理阻塞队列任务,直接返回null
           // 如果线程池状态是SHUTDOWN,并且阻塞队列是空的,直接返回null
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();  // 如果可以返回null,先扣减工作线程个数
                return null;  // 返回null,结束runWorker的while循环
            }
            // 基于ctl拿到工作线程个数
            int wc = workerCountOf(c);

            // 核心线程允许超时,timed为true
            // 工作线程个数大于核心线程数,timed为true
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
            // 如果工作线程个数,大于最大线程数。(一般情况不会满足),把他看成false
            // 第二个判断: 只要工作线程数小于等于核心线程数,必然为false
            // 即便工作线程个数大于核心线程数了,此时第一次循环也不会为true,因为timedOut默认值是false
            // 考虑第二次循环了,因为循环内部必然有修改timeOut的位置
            if ((wc > maximumPoolSize || (timed && timedOut))
                // 要么工作线程还有,要么阻塞队列为空,并且满足上述条件后,工作线程才会走到if内部,结束工作线程
                && (wc > 1 || workQueue.isEmpty())
                ) {
                // 第二次循环才有可能到这。
                // 正常结束,工作线程 - 1,因为是CAS操作,如果失败了,重新走for循环
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
            // 工作线程从阻塞队列拿任务
            try {
                 // 如果是核心线程,timed是false,如果是非核心线程,timed就是true
                Runnable r = timed ?
                    // 如果是非核心,走poll方法,拿任务,等待一会
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    // 如果是核心,走take方法,死等。
                    workQueue.take();
                 // 从阻塞队列拿到的任务不为null,这边就正常返回任务,去执行
                if (r != null)
                    return r;
                / 说明当前线程没拿到任务,将timeOut设置为true,在上面就可以返回null退出了。
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

9. ThreadPoolExecutor的shutdownNow方法

shutDownNow方法,shutdownNow不会处理阻塞队列的任务,将任务全部给你返回了。

    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //底层安全相关的,没有关注
            checkShutdownAccess();
            //  // 将线程池状态修改为STOP
            advanceRunState(STOP);
            // 无论怎么,直接中断工作线程。
            interruptWorkers();
            // 将阻塞队列的任务全部扔到List集合中。
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }
    
    
    private void advanceRunState(int targetState) {
        // 死循环。
        for (;;) {
            // 获取ctl属性的值
            int c = ctl.get();
            //第一个判断:判断线程池状态是否已经大于等于 STOP了,如果是 就 break
            //第二个判断:如果第一个判断没劲,就会尝试CAS设置ctl更改为STOP状态,如果修改成功 break
            if (runStateAtLeast(c, targetState) ||
                ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
                break;
        }
    }
    // 无论怎么,直接中断工作线程。
    private void interruptWorkers() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 遍历HashSet,拿到所有的工作线程,直接中断。
            for (Worker w : workers)
                w.interruptIfStarted();
        } finally {
            mainLock.unlock();
        }
    }
    // 移除阻塞队列,内容全部扔到List集合中
    private List<Runnable> drainQueue() {
        BlockingQueue<Runnable> q = workQueue;
        ArrayList<Runnable> taskList = new ArrayList<Runnable>();
        // 阻塞队列自带的,直接清空阻塞队列,内容扔到List集合
        q.drainTo(taskList);
        // 为了避免任务丢失,重新判断,是否需要编辑阻塞队列,重新扔到List
        if (!q.isEmpty()) {
            for (Runnable r : q.toArray(new Runnable[0])) {
                if (q.remove(r))
                    taskList.add(r);
            }
        }
        return taskList;
    }
    //查看当前线程池是否可以变为TERMINATED状态
    final void tryTerminate() {
        //死循环
        for (;;) {
            //获取状态
            int c = ctl.get();
            //isRunning(c) : 判断状态是否是RUNNING,如果是就直接 return
            //runStateAtLeast(c, TIDYING): 如果状态已经大于等于TIDYING,马上就要凉凉,直接return。
            //(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())  如果状态是SHUTDOWN,但是阻塞队列还有任务,直接告辞。
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            // 如果还有工作线程
            if (workerCountOf(c) != 0) { // Eligible to terminate
                // 再次中断工作线程
                interruptIdleWorkers(ONLY_ONE);
                 // 告辞,等你工作线程全完事,我这再尝试进入到TERMINATED状态
                return;
            }
             // 加锁,为了可以执行Condition的释放操作
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
            // 将线程池状态修改为TIDYING状态,如果成功,继续往下走
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                     // 这个方法是空的,如果你需要在线程池关闭后做一些额外操作,这里你可以自行实现
                        terminated();
                    } finally {
                      // 最终修改为TERMINATED状态
                        ctl.set(ctlOf(TERMINATED, 0));
                    / 线程池提供了一个方法,主线程在提交任务到线程池后,是可以继续做其他操作的。
                    // 咱们也可以让主线程提交任务后,等待线程池处理完毕,再做后续操作
                    // 这里线程池凉凉后,要唤醒哪些调用了awaitTermination方法的线程
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

10. ThreadPoolExecutor的shutdown方法

再次shutdown方法,可以从RUNNING状态转变为SHUTDOWN
shutdown状态下,不会中断正在干活的线程,而且会处理阻塞队列中的任务

public void shutdown() {
    // 加锁。。
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 不看。
        checkShutdownAccess();
        // 里面是一个死循环,将线程池状态修改为SHUTDOWN
        advanceRunState(SHUTDOWN);
        // 中断空闲线程
        interruptIdleWorkers();
        // 说了,这个是为了ScheduleThreadPoolExecutor准备的,不管
        onShutdown(); 
    } finally {
        mainLock.unlock();
    }
    // 尝试结束线程
    tryTerminate();
}

// 中断空闲线程
private void interruptIdleWorkers(boolean onlyOne) {
    // 加锁
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (Worker w : workers) {
            Thread t = w.thread;
            // 如果线程没有中断,那么就去获取Worker的锁,基于tryLock可知,不会中断正在干活的线程
            if (!t.isInterrupted() && w.tryLock()) {
                try {
                    // 会中断空闲线程
                    t.interrupt();
                } catch (SecurityException ignore) {
                } finally {
                    w.unlock();
                }
            }
            if (onlyOne)
                break;
        }
    } finally {
        mainLock.unlock();
    }
}
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容