Java線程池知識必備

線程池

簡介

線程池的創建

new  ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit milliseconds,
BlockingQueue<Runnable> runnableTaskQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler);
  • corePoolSize(線程池基本大小)

這是一個判斷該線程池是否要新建一個新的線程的標準值,如果當前線程池中的線程數小於corePoolSize,
則在接到新的請求任務時新建一個線程來處理,反之則把任務放到
BlockingQueue中,由線程池中空的線程從BlockingQueue中取出並處理;

  • maximumPoolSize(線程池最大大小)

線程池最大的線程數,當大於該值的時候則讓RejectedExecutionHandler拒絕處理;

  • keepAliveTime
    當線程池中大於corePoolSize的時候,部分多餘的空線程會等待keepAliveTime時間,如果沒有請求處理超過該時間則自行銷燬;

  • BlockingQueue(任務隊列)
    保存等待任務執行的阻塞隊列,有以下幾種:

    • ArrayBlockingQueue:數組隊列,先進先出;
    • LinkedBlockingQueue:鏈表隊列,先進先出,吞吐量大於ArrayBlockingQueue;
    • SynchronousQueue:一個不存儲元素的隊列,每插入一個任務必須等到另一個線程調用移除操作,否則處於阻塞狀態;吞吐量高於LinkedBlockingQueue,newCachedThreadPool使用的就是這個隊列;
    • PriorityBlockingQueue:一個優先級無限阻塞的隊列;
  • RejectedExecutionHandler(飽和策略)
    當線程池處於飽和狀態下,對於提交的新任務必須要有一種策略來處理;

提交任務

  • execute(new Runnable(){} )
    沒有返回值

     threadsPool.execute(new Runnable() {
          @Override
          public void run() {
              // TODO Auto-generated method stub
          }
      });
    
  • commit(new callable(){}) 返回future對象

          Future future = mThreadPoolExecutor.submit(new Callable() {
              @Override
              public Object call() throws Exception {
                  return null;
              }
          });
          --------------------------------------------------
    
          try {
              Object o = future.get();//阻塞 直到結果準備就緒
          } catch (InterruptedException e) {
              //中斷異常
              e.printStackTrace();
          } catch (ExecutionException e) {
              //無法執行異常
              e.printStackTrace();
          } finally {
              //關閉線程池
              mThreadPoolExecutor.shutdown();
          }
      }
    

關閉任務

  • 原理
    遍歷所有的線程,逐個調用線程的interrupt方法來中斷線程;
  • shutdown
    執行shutdown後,遍歷線程池中所有的線程,將狀態修改爲SHUTDOWN狀態,然後中斷正在執行任務的線程;
  • shutdownNow
    執行shutdownNow後,遍歷線程池中所有的線程,將所有線程的狀態修改爲STOP狀態,然後嘗試停止所有的線程任務

工作原理

  • 工作流程示意圖

工作示意圖

  • 源碼分析

  • 工作線程

合理配置線程池

  • 任務特性

    • 任務的性質:CPU密集型任務,IO密集型的任務,混合型任務;
    • 任務的優先級:高,中,低;
    • 任務的執行時間:長、中、短;
    • 任務的依賴性,是否依賴其他系統資源,比如數據庫連接。
  • 配置意見

    • CPU密集型建議使用線程數儘可能少的線程池,IO密集型任務由於線程並不是一直在工作,所以建議使用線程數較多的線程池;
    • 優先級不同任務可以使用PriorityBlockingProcessors任務隊列來處理,讓優先級更高的來處理(!注意:如果一直是優先級搞的任務在處理,則優先級低的任務可能無法得到處理;
    • 時間不同的任務可以交給不同規模的線程池來處理,也可以交給優先級隊列,讓時間短的任務先執行;
    • 依賴數據庫連接池的任務,由於提交SQL後需要等待返回結果,所以等待的時間越長,CPU空閒的時間越長,爲了提高CPU的利用率,可以通過增大線程池的線程數。
    • 建議使用有界隊列,這樣更加穩定安全,防止撐爆內存(如果線程一直處於阻塞狀態,新的任務來的時候就會新建新的線程,直到內存不足)。

線程池的監控

  • 部分線程池的屬性參數

    • taskCount:線程池需要執行的任務數量;
    • completedTaskCont: 已經完成的任務數量;
    • largestPoolSize: 線程池曾經創建過的最大線程數,可以看看是否大於最大線程數,是否滿過;
    • getPoolSize: 線程池的線程數量,線程池不銷燬,池中的線程不會自動銷燬
    • getAliveCount:活動狀態的線程數。
  • 通過擴展線程池進行監控

    • 繼承線程池;
    • 重寫beforeExecute,afterExecute和terminated方法。

常用線程池

  • FixedThreadPool 定長併發線程池

    • 源碼

      public static ExecutorService newFixedThreadPool(int nThreads) {
          return new ThreadPoolExecutor(nThreads, nThreads,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>());
      }
      
    • 特點:
      可以創建固定的線程數,當線程數達到corePoolSize的時候,再添加任務就放到LinkedBlockingQueue這個無界的隊列裏邊,等待空閒的線程來取任務執行任務,空閒線程不會被回收;
  • SingleThreadExecutor 順序執行線程池

    • 源碼

      public static ExecutorService newSingleThreadExecutor() {
           return new FinalizableDelegatedExecutorService
                              (new ThreadPoolExecutor(1, 1,
                              0L, TimeUnit.MILLISECONDS,
                              new LinkedBlockingQueue<Runnable>()));
      }
      
    • 特點
      corePoolSize爲1,既最多只能有一個線程工作,當其他任務來的時候都放到LinkedBlockingQueue任務隊列裏邊,等待線程工作完後,再從隊列裏邊取,逐個執行,相當於順序執行;
  • CachedThreadPool “無限”容量可緩存線程池

    • 源碼

      public static ExecutorService newCachedThreadPool() {
              return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                60L, TimeUnit.SECONDS,
                                new SynchronousQueue<Runnable>());
      }
      
    • 特點
      • SynchronousQueue是一個沒有容量的阻塞隊列,每個插入必須有對應的移除操作;
      • 如果沒有線程去從SynchronousQueue從事移除的工作,那麼就會新建一個線程來執行任務,如果一直這麼下去,就可以能因爲創建過多的線程耗盡CPU資源;
      • 如果空閒的線程等待時間超過60秒,而且沒有新的任務,會自動被回收。
  • ScheduledThreadPool 定時線程池

參考資料:

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