1. 程式人生 > 程式設計 >ThreadPoolExecutor執行緒池原始碼解讀keepAliveTime 空閒過期時間作用

ThreadPoolExecutor執行緒池原始碼解讀keepAliveTime 空閒過期時間作用

keepAliveTime引數主要是把除了核心執行緒 其他執行緒當超過等待時間keepAliveTime 就會進行執行緒移除 接下來主要講下執行緒是如何建立 執行 然後操作等待時間是如何移除的 先介紹兩個執行緒池的核心引數

  1. HashSet workers工作類集合

Worker這個其實就是儲存線上程池裡的執行緒 實現了Runnable介面 當執行緒池中開啟10個執行緒 就會建立10個Worker類 這些worker會儲存在workers工作類集合中 Worker類裡面主要有一下兩個核心引數

    private final class Worker
        extends AbstractQueuedSynchronizer
implements Runnable
{ /** 執行Worker的執行緒 */ final Thread thread; /** 這裡存放的是使用方傳給執行緒池的執行緒 */ Runnable firstTask; Worker(Runnable firstTask) { setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; // 把自己本身worker放入到thread中 後面直接執行thread.start 就會執行Worker的run方法 然後在run方法中執行firstTask.run
this.thread = getThreadFactory().newThread(this); } 複製程式碼
  1. BlockingQueue< Runnable > workQueue 等待佇列

這個其實就是當執行緒達到核心執行緒數以後 會把待執行的佇列放入到等待佇列中等待執行

execute(Runnable command)

當第一次執行執行緒池的execute 會因為當前執行緒數小於核心執行緒數而執行這段程式碼 當然核心執行緒數設定為0除外

        if (workerCountOf(c) < corePoolSize) {
            if
(addWorker(command,true)) return; c = ctl.get(); } 複製程式碼

這裡核心是addWorker方法 這裡會把傳進來當需要執行的執行緒command放入到剛剛說的worker工作類中 然後再放入到workers工作類集合中 然後啟動worker執行緒

          //只拉取核心程式碼
          // firstTask為execute(Runnable command)傳入的需要執行的執行緒
           w = new Worker(firstTask);
           final Thread t = w.thread;
   	    workers.add(w);
           t.start();
複製程式碼

之後看下Worker的run方法 裡面會先執行runWorker方法 然後在方法中執行需要執行的執行緒 這裡核心主要程式碼有兩句

//task為前面execute(Runnable command)傳入的需要執行的執行緒 如果不為空則執行執行task.run 如果為空 則通過getTask() 獲取等待佇列workQueue裡需要執行的執行緒
while (task != null || (task = getTask()) != null)
複製程式碼

重點 keepAliveTime的體現核心就是getTask()方法中

當前執行的執行緒是核心執行緒 則timed=false

    //只拉取核心程式碼
     Runnable r = timed ?
     workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS) :
     workQueue.take();
複製程式碼

就會執行workQueue.take()從等待佇列裡獲取一個需要執行的執行緒任務 因為 BlockingQueue< Runnable > workQueue是阻塞佇列 如果裡面沒有需要執行的執行緒任務 則會一直阻塞等待 一直到獲取執行緒任務

       workQueue.take();
複製程式碼

重點 如果timed=true 執行workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS) : keepAliveTime就是在這裡發揮作用的

poll這行程式碼就是會等待keepAliveTime設定的時間 超過超時時間就返回null

    workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS) :
複製程式碼

當超過超時時間 getTask就會返回null

while (task != null || (task = getTask()) != null)
複製程式碼

推出迴圈 並且設定

completedAbruptly = false;
複製程式碼

然後執行processWorkerExit方法

processWorkerExit(w,completedAbruptly)
複製程式碼

processWorkerExit這裡核心就是把當前執行的worker從worker工作類集合中刪除

workers.remove(w);
複製程式碼

然後還有一段邏輯

         if (!completedAbruptly) {
         //allowCoreThreadTimeOut預設為false  如果設定為true 則代表執行緒池中corePoolSize執行緒空閒時間達到keepAliveTime也將關閉  上面說的timed 如果allowCoreThreadTimeOut為true 則timed也會為true 也就會進入poll方法 通過這個來實現超時關閉核心執行緒數
             int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
             if (min == 0 && ! workQueue.isEmpty())
                 min = 1;
              //當前執行緒數大於核心執行緒數 直接返回 然後執行緒關閉
             if (workerCountOf(c) >= min)
                 return; // replacement not needed
         }
         addWorker(null,false);
複製程式碼

注意上面的 addWorker(null,false); 這個其實是個注意點優化點 當執行一開始自己寫的Runnable command 的run方法如果執行異常 也會走上面的程式碼completedAbruptly=true 然後執行addWorker(null,false); 建立一個空的worker執行緒繼續執行

重點:所以run裡最好是把所有的異常捕獲 而不要丟擲 不然丟擲異常 就會立刻銷燬執行緒 然後建立一個新執行緒 執行緒池的作用就沒有