Thread.ThreadPool

線程池的好處:數組

第一:下降資源消耗。經過重複利用已建立的線程下降線程建立和銷燬形成的消耗。緩存

第二:提升響應速度。當任務到達時,任務能夠不須要的等到線程建立就能當即執行。服務器

第三:提升線程的可管理性。線程是稀缺資源,若是無限制的建立,不只會消耗系統資源,還會下降系統的穩定性,使用線程池能夠進行統一的分配,調優和監控。可是要作到合理的利用線程池,必須對其原理了如指掌。併發

線程池的建立

咱們能夠經過ThreadPoolExecutor來建立一個線程池。異步

1 new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
2 keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);

建立一個線程池須要輸入幾個參數:spa

  • corePoolSize(線程池的基本大小):當提交一個任務到線程池時,線程池會建立一個線程來執行任務,即便其餘空閒的基本線程可以執行新任務也會建立線程,等到須要執行的任務數大於線程池基本大小時就再也不建立。若是調用了線程池的prestartAllCoreThreads方法,線程池會提早建立並啓動全部基本線程。
  • runnableTaskQueue(任務隊列):用於保存等待執行的任務的阻塞隊列。能夠選擇如下幾個阻塞隊列。
  1. ArrayBlockingQueue:是一個基於數組結構的有界阻塞隊列,此隊列按 FIFO(先進先出)原則對元素進行排序。
  2. LinkedBlockingQueue:一個基於鏈表結構的阻塞隊列,此隊列按FIFO (先進先出) 排序元素,吞吐量一般要高於ArrayBlockingQueue。靜態工廠方法Executors.newFixedThreadPool()使用了這個隊列。
  3. SynchronousQueue:一個不存儲元素的阻塞隊列。每一個插入操做必須等到另外一個線程調用移除操做,不然插入操做一直處於阻塞狀態,吞吐量一般要高於LinkedBlockingQueue,靜態工廠方法Executors.newCachedThreadPool使用了這個隊列。
  4. PriorityBlockingQueue:一個具備優先級得無限阻塞隊列。
  • maximumPoolSize(線程池最大大小):線程池容許建立的最大線程數。若是隊列滿了,而且已建立的線程數小於最大線程數,則線程池會再建立新的線程執行任務。值得注意的是若是使用了無界的任務隊列這個參數就沒什麼效果。
  • ThreadFactory:用於設置建立線程的工廠,能夠經過線程工廠給每一個建立出來的線程設置更有意義的名字,Debug和定位問題時很是又幫助。

RejectedExecutionHandler(飽和策略):當隊列和線程池都滿了,說明線程池處於飽和狀態,那麼必須採起一種策略處理提交的新任務。這個策略默認狀況下是AbortPolicy,表示沒法處理新任務時拋出異常。如下是JDK1.5提供的四種策略。n  AbortPolicy:直接拋出異常。線程

  1. CallerRunsPolicy:只用調用者所在線程來運行任務。
  2. DiscardOldestPolicy:丟棄隊列裏最近的一個任務,並執行當前任務。
  3. DiscardPolicy:不處理,丟棄掉。
  4. 固然也能夠根據應用場景須要來實現RejectedExecutionHandler接口自定義策略。如記錄日誌或持久化不能處理的任務。
  • keepAliveTime(線程活動保持時間):線程池的工做線程空閒後,保持存活的時間。因此若是任務不少,而且每一個任務執行的時間比較短,能夠調大這個時間,提升線程的利用率。
  • TimeUnit(線程活動保持時間的單位):可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

線程池的executor,submit區別在於,execute不用返回結果,submit返回furture包裝的結果值rest

線程池的關閉

shutdown:shutdown的原理是隻是將線程池的狀態設置成SHUTDOWN狀態,而後中斷全部沒有正在執行任務的線程日誌

shutdownNow:shutdownNow的原理是遍歷線程池中的工做線程,而後逐個調用線程的interrupt方法來中斷線程,因此沒法響應中斷的任務可能永遠沒法終止。shutdownNow會首先將線程池的狀態設置成STOP,而後嘗試中止全部的正在執行或暫停任務的線程,並返回等待執行任務的列表。code

只要調用了這兩個關閉方法的其中一個,isShutdown方法就會返回true。當全部的任務都已關閉後,才表示線程池關閉成功,這時調用isTerminaed方法會返回true。至於咱們應該調用哪種方法來關閉線程池,應該由提交到線程池的任務特性決定,一般調用shutdown來關閉線程池,若是任務不必定要執行完,則能夠調用shutdownNow。

3.    線程池的分析

流程分析:線程池的主要工做流程以下圖:

從上圖咱們能夠看出,當提交一個新任務到線程池時,線程池的處理流程以下:

  1. 首先線程池判斷基本線程池是否已滿?沒滿,建立一個工做線程來執行任務。滿了,則進入下個流程。
  2. 其次線程池判斷工做隊列是否已滿?沒滿,則將新提交的任務存儲在工做隊列裏。滿了,則進入下個流程。
  3. 最後線程池判斷整個線程池是否已滿?沒滿,則建立一個新的工做線程來執行任務,滿了,則交給飽和策略來處理這個任務。

 

一:newCachedThreadPool-可變尺寸的線程池(緩存線程池) 
(1)緩存型池子,先查看池中有沒有之前創建的線程,若是有,就reuse(重用),若是沒有,就創建一個新的線程加入池中; 
(2)緩存型池子,一般用於執行一些生存週期很短的異步型任務;所以一些面向鏈接的daemon型server中用得很少; 
(3)能reuse(重用)的線程,必須是timeout IDLE內的池中線程,缺省timeout是60s,超過這個IDLE時長,線程實例將被終止及移出池; 
(4)注意,放入CachedThreadPool的線程沒必要擔憂其結束,超過TIMEOUT不活動,其會自動被終止。

二:newFixedThreadPool-固定大小的線程池 
(1)newFixedThreadPool與cacheThreadPool差很少,也是能reuse就用,但不能隨時建新的線程; 
(2)其獨特之處:任意時間點,最多隻能有固定數目的活動線程存在,此時若是有新的線程要創建,只能放在另外的隊列中等待,直到當前的線程中某個線程終止直接被移出池子; 
(3)和cacheThreadPool不一樣,FixedThreadPool沒有IDLE機制(可能也有,但既然文檔沒提,確定很是長,相似依賴上層的TCP或UDP IDLE機制之類的),因此FixedThreadPool多數針對一些很穩定很固定的正規併發線程,多用於服務器; 
(4)從方法的源代碼看,cache池和fixed池調用的是同一個底層池,只不過參數不一樣:
fixed池線程數固定,而且是0秒IDLE(無IDLE);
cache池線程數支持0-Integer.MAX_VALUE(顯然徹底沒考慮主機的資源承受能力),60秒IDLE。

三:ScheduledThreadPool-調度線程池 
(1)調度型線程池; 
(2)這個池子裏的線程能夠按schedule依次delay執行,或週期執行。

四:SingleThreadExecutor-單例線程池 
(1)單例線程,任意時間池中只能有一個線程;  (2)用的是和cache池和fixed池相同的底層池,但線程數目是1-1,0秒IDLE(無IDLE)。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息