zoukankan      html  css  js  c++  java
  • 线程池关闭源码

    线程池的状态如下  

       private static final int RUNNING    = -1 << COUNT_BITS;//111 + 29个0
        private static final int SHUTDOWN   =  0 << COUNT_BITS;//全是0
        private static final int STOP       =  1 << COUNT_BITS;//001 + 29个0
        private static final int TIDYING    =  2 << COUNT_BITS;//010 + 29个0
        private static final int TERMINATED =  3 << COUNT_BITS;//011 + 29个0
    COUNT_BITS 为29。-1在计算机中的补码是1111 1111,当左移29位后,就是最高的三位是111,剩下29位都是0。
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static int ctlOf(int rs, int wc) { return rs | wc; }

      所以这个ctl的初始值就是111 + 29个0

      二 shutdown

     public void shutdown() {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                checkShutdownAccess();//忽略
                advanceRunState(SHUTDOWN);//高三位是000,除非ctl已经比000还大
                interruptIdleWorkers();
                onShutdown(); // hook for ScheduledThreadPoolExecutor
            } 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;//如果线程在工作,或者没有阻塞,那么该方法什么都没有干
                    if (!t.isInterrupted() && w.tryLock()) {//如果tryLock能够返回true,说明啥说明该线程没有在干活,很可能是在从阻塞队列task,由于队列里没有任务导致阻塞
                        try {
                            t.interrupt();//执行中断,在worker的getTask方法是会抛出异常的,这会导致线程池中的线程退出
                        } catch (SecurityException ignore) {
                        } finally {
                            w.unlock();
                        }
                    }
                    if (onlyOne)
                        break;
                }
            } finally {
                mainLock.unlock();
            }
        }

    真正的执行关闭线程逻辑在 tryTerminate,前面只是在打扫战场,打扫的是已经空闲下来的线程,剩下的是

    final void tryTerminate() {
            for (;;) {
                int c = ctl.get();
                if (isRunning(c) ||
                    runStateAtLeast(c, TIDYING) ||
                    (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))//如果执行过shutdown 前两个判断就都是false,第三个条件如果任务队列不为空,就直接返回
                    return;
                if (workerCountOf(c) != 0) { // Eligible to terminate 这个方法的意义,应该是把关闭行为传递下去,但是其实对于工作中的线程不会产生影响,但是如果任务队列为空同时执行过shutdown后,
                    interruptIdleWorkers(ONLY_ONE);//中断可能在take方法阻塞的线程,这样线程就会执行完毕,线程数减一,此时线程池状态是SHUTDOWN,所以即使work数量小于coreSize也不会再次添加worker
                    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
            }
        }

       如果单看这个方法,第一次看人会很懵,因为前两个if,就会发现根本不会关闭线程池。想要理解这个问题,要结合runWorker方法和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.
                if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                    decrementWorkerCount();
                    return null;//直接返回null
                }

      这样worker线程的循环条件不满足,就会终止,执行finally里面的方法

    final void runWorker(Worker w) {
            ...
            try {
                while (task != null || (task = getTask()) != null) {
                    ...
                }
                completedAbruptly = false;
            } finally {
                processWorkerExit(w, completedAbruptly);
            }
        }

      把线程remove掉,同时再次执行tryTerminate

    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.remove(w);
            } finally {
                mainLock.unlock();
            }
    
            tryTerminate();

    三 shutDownNow

      有了shutDown的分析,shutDownNow有几处差别,

      1 中断所有的worker,而shutDown是中断空闲worker

      2 把任务队列拷贝出来,并清空

      3 在上面的 getTask里判断大于等于STOP就不会判断任务队列直接返回null,这样worker线程就会直接退出循环

      

     
  • 相关阅读:
    分支(选择)语句练习——7月22日
    语句:分支语句、switch case ——7月22日
    C#语言基础——7月21日
    进制转换——7月20日
    运行Tomcat报错 解决方法
    Mybatis面试题
    java面试题02
    当你没有能力去改变别人命运的时候 就不要随意去伸出援手......
    快速学习MD5的方法
    java面试题01
  • 原文地址:https://www.cnblogs.com/juniorMa/p/13955811.html
Copyright © 2011-2022 走看看