java線程池ThreadPoolExecutor的keepAliveTime=0時,表示超過core線程數的線程在空閑時立即結束!!!


今天同事突然提出問題說用哪個線程池好,newFixedThreadPool和newCacheThreadPool里選擇,說固定大小線程池keepAliveTime=0,線程空閑會立馬回收線程從而節約資源,然后另外一個同事說,0是代表永遠不回收,我記憶里也是記得0是永久存活,因為網上很多博客啊,資料啊都是說的0表示線程永久存活在空閑的時候。前面那位同事也是從字面上認為的,沒有經過驗證,覺得-1才是永久不回收,然后各自進行了一波研究分析。

經過看源碼,發現keepAliveTime<0是不行的,直接報錯,也就是同事的猜測-1才是不回收 是錯誤的,看下面代碼圖示(別問我怎么給代碼里部分標紅,直接用瀏覽器F12自己編輯頁面寫標簽樣式進去的。。)

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;
    }
然后找keepAliveTime的使用一時半會也沒找到,就用代碼測試了,發現設置keepAliveTime=0核心線程數確實沒有回收,后面同事說在並發病程的藝術那本書上有一段描述

“當線程池中的線程數大於corePoolSize時,keepAliveTime為多余的空閑線程等待新任務的 最長時間,超過這個時間后多余的線程將被終止。這里把keepAliveTime設置為0L,意味着多余 的空閑線程會被立即終止。”

同事又開始迷茫了,我一開始沒細看,覺得說的不對,后面反復閱讀,發現這段文字描述的是說keepAliveTime控制的是非核心線程數的回收,也就是0的時候,非核心線程數會在空閑的時候回收,並不是說核心的會回收。

為了驗證結果,我們就用代碼進行了測試,測試代碼如下:

package com.xhs.concurrent.threaddemo.sync;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
 
/**
 * @author xuhan  build  2019/4/23
 */
public class ExecutorsDemo implements Runnable{
 
    private int i=0;
 
    public ExecutorsDemo(int i) {
        this.i = i;
    }
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1,2,0, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(1));
        for(int i=0;i<3;i++){
            executor.execute(new ExecutorsDemo(i));
        }
        while(true){
            System.out.println("總線程數:"+executor.getPoolSize()+"當前活躍線程數:"+executor.getActiveCount());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void run() {
        System.out.println("i="+i+" Thread = "+Thread.currentThread().getName());
        if(i>=1){
            try {
                TimeUnit.SECONDS.sleep(1);
                System.out.println("i="+i+" sleep 1 s結束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else{
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println("i="+i+" sleep 3 s結束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
設置核心線程數和非核心線程數分別為1個,隊列容量為1,進入3個runnable:

第一個創建主線程,第二個進入隊列,第三個則創建非主線程運行,

輸出結果為

i=0 Thread = pool-1-thread-1
i=2 Thread = pool-1-thread-2
總線程數:2當前活躍線程數:2
總線程數:2當前活躍線程數:2
i=2 sleep 1 s結束
i=1 Thread = pool-1-thread-2
總線程數:2當前活躍線程數:2
總線程數:2當前活躍線程數:2
i=1 sleep 1 s結束
總線程數:1當前活躍線程數:1
總線程數:1當前活躍線程數:1
i=0 sleep 3 s結束
總線程數:1當前活躍線程數:0
可以看到非核心數線程執行完畢之后,隊列中的task進入繼續執行,等再次進入隊列的task結束后,可以看到總線程數減少了1,而等核心線程執行完畢后,發現總線程數沒有減少,但活躍線程數減少,也就是核心線程數沒有回收。書上說的是正確的,大部分網上的博客說的keepAliveTime=0永久不回收是有出入的。

如果要設置核心線程的回收,則需要設置

executor.allowCoreThreadTimeOut(true);
但這是keepAliveTime必須要>0才行,否則會拋出異常!!!

throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
如果看了之后覺得有問題,希望各位指點一番!!謝謝!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM