Java線程池是如何保證核心線程不被銷燬的!

首先看一下線程被銷燬的代碼:

// 當線程獲取不到tasks, 就調用processWorkerExit方法, 處理線程退出
    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); // 將線程從HashSet中移除
        } finally {
            mainLock.unlock();
        }

        tryTerminate();

        int c = ctl.get();
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }
    }

照理說不管是核心線程還是非核心線程,blockingQueue不可能一直都有task,總有處理完的時候,一旦blockingQueue中沒有task可處理,那麼這個線程就一定會被remove,因爲processWorkerExit方法是寫在finally裏面的;

// 線程池worker處理task方法
    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        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
                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 {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

那麼,如何保證核心線程不退出呢?

再來明確一個概念,所謂的核心線程與非核心線程,在線程池的數據結構中並沒有明確區分,只要線程池剩餘的線程數小於等於corePoolSize,那麼剩下的線程都可以稱爲核心線程;

再有,一個核心線程要想不被銷燬,那麼只有一種可能,那就是線程等待,等待有新的task到來;

換句話說:一旦線程池的線程個數小於等於corePoolSize,task = getTask() 是永遠不會返回null的(非異常情況)。

我們來看看getTask方法是怎麼處理的:

// 通過上面分析,可以得出結論:
// 1,線程數大於corePoolSize,當隊列無task或者線程池狀態異常時return null
// 2,線程數小於等於corePoolSize,getTask不會返回null,異常情況除外
    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判斷也很重要,如果調用了shutdown/shutdownNow方法,那麼“核心線程”也會返回null
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c); // 取線程數

            // Are workers subject to culling?
            // allowCoreThreadTimeOut = false
            // timed = true 表示存在非核心線程
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            // wc > maximumPoolSize = false 一般不會出現這種情況,所以是false
            // 這個if條件成立的前提:必須存在非核心線程【關鍵】
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null; // 這個null就是非核心線程被銷燬的罪魁禍首
                continue;
            }

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r; // 能取到任務就返回,否則設置timedOut進去死循環
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

——綜上,我們總結了Java線程池的一個小細節! 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章