線程池的好處:segmentfault
1,由於線程是比較昂貴的資源,避免大量重複建立銷燬線程,使用者不用關心建立銷燬線程。服務器
2,用戶提交的任務可以及時的獲得處理,提升響應速度。多線程
3,可以更好的監控和管理線程。函數
這些參數這樣描述起來很空洞,下面結合執行任務的流程來看一下。spa
當線程池大小 >= corePoolSize 且 隊列未滿時,這時線程池使用者與線程池之間構成了一個生產者-消費者模型。線程池使用者生產任務,線程池消費任務,任務存儲在BlockingQueue中,注意這裏入隊使用的是offer,當隊列滿的時候,直接返回false,而不會等待。操作系統
當線程處於空閒狀態時,線程池須要對它們進行回收,避免浪費資源。但空閒多長時間回收呢,keepAliveTime就是用來設置這個時間的。默認狀況下,最終會保留corePoolSize個線程避免回收,即便它們是空閒的,以備不時之需。但咱們也能夠改變這種行爲,經過設置allowCoreThreadTimeOut(true)
。.net
線程池所使用的緩衝隊列,該緩衝隊列的長度決定了可以緩衝的最大數量,緩衝隊列有三種通用策略:線程
1) 直接提交。工做隊列的默認選項是 SynchronousQueue,它將任務直接提交給線程而不保持它們。在此,若是不存在可用於當即運行任務的線程,則試圖把任務加入隊列將失敗,所以會構造一個新的線程。此策略能夠避免在處理可能具備內部依賴性的請求集時出現鎖。直接提交一般要求無界 maximumPoolSizes 以免拒絕新提交的任務。當命令以超過隊列所能處理的平均數連續到達時,此策略容許無界線程具備增加的可能性;code
2) 無界隊列。使用無界隊列(例如,不具備預約義容量的 LinkedBlockingQueue)將致使在全部 corePoolSize 線程都忙時新任務在隊列中等待。這樣,建立的線程就不會超過 corePoolSize。(所以,maximumPoolSize 的值也就無效了。)當每一個任務徹底獨立於其餘任務,即任務執行互不影響時,適合於使用無界隊列;例如,在 Web 頁服務器中。這種排隊可用於處理瞬態突發請求,當命令以超過隊列所能處理的平均數連續到達時,此策略容許無界線程具備增加的可能性;blog
3) 有界隊列。當使用有限的 maximumPoolSizes 時,有界隊列(如 ArrayBlockingQueue)有助於防止資源耗盡,可是可能較難調整和控制。隊列大小和最大池大小可能須要相互折衷:使用大型隊列和小型池能夠最大限度地下降 CPU 使用率、操做系統資源和上下文切換開銷,可是可能致使人工下降吞吐量。若是任務頻繁阻塞(例如,若是它們是 I/O 邊界),則系統可能爲超過您許可的更多線程安排時間。使用小型隊列一般要求較大的池大小,CPU 使用率較高,可是可能遇到不可接受的調度開銷,這樣也會下降吞吐量。
unit:參數keepAliveTime的時間單位,有7種取值,在TimeUnit類中有7種靜態屬性:
TimeUnit.DAYS; //天 TimeUnit.HOURS; //小時 TimeUnit.MINUTES; //分鐘 TimeUnit.SECONDS; //秒 TimeUnit.MILLISECONDS; //毫秒 TimeUnit.MICROSECONDS; //微妙 TimeUnit.NANOSECONDS; //納秒
Executors 是提供了一組工廠方法用於建立經常使用的 ExecutorService ,分別是 FixedThreadPool,CachedThreadPool 以及 SingleThreadExecutor。這三種ThreadPoolExecutor都是調用 ThreadPoolExecutor 構造函數進行建立,區別在於參數不一樣。
下面是 Executors 類 newFixedThreadPool 方法的源碼:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
能夠看到 corePoolSize 和 maximumPoolSize 設置成了相同的值,此時不存在線程數量大於核心線程數量的狀況,因此KeepAlive時間設置不會生效。任務隊列使用的是不限制大小的 LinkedBlockingQueue ,因爲是無界隊列因此容納的任務數量沒有上限。
所以,FixedThreadPool的行爲以下:
從線程池中獲取可用線程執行任務,若是沒有可用線程則使用ThreadFactory建立新的線程,直到線程數達到nThreads
線程池線程數達到nThreads之後,新的任務將被放入隊列
FixedThreadPool的優勢是可以保證全部的任務都被執行,永遠不會拒絕新的任務;同時缺點是隊列數量沒有限制,在任務執行時間無限延長的這種極端狀況下會形成內存問題。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
這個工廠方法中使用無界LinkedBlockingQueue,並的將線程數設置成1,除此之外還使用FinalizableDelegatedExecutorService類進行了包裝。這個包裝類的主要目的是爲了屏蔽ThreadPoolExecutor中動態修改線程數量的功能,僅保留ExecutorService中提供的方法。雖然是單線程處理,一旦線程由於處理異常等緣由終止的時候,ThreadPoolExecutor會自動建立一個新的線程繼續進行工做。
SingleThreadExecutor 適用於在邏輯上須要單線程處理任務的場景,同時無界的LinkedBlockingQueue保證新任務都可以放入隊列,不會被拒絕;缺點和FixedThreadPool相同,當處理任務無限等待的時候會形成內存問題。
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
SynchronousQueue是一個只有1個元素的隊列,入隊的任務須要一直等待直到隊列中的元素被移出。核心線程數是0,意味着全部任務會先入隊列;最大線程數是Integer.MAX_VALUE,能夠認爲線程數量是沒有限制的。KeepAlive時間被設置成60秒,意味着在沒有任務的時候線程等待60秒之後退出。CachedThreadPool對任務的處理策略是提交的任務會當即分配一個線程進行執行,線程池中線程數量會隨着任務數的變化自動擴張和縮減,在任務執行時間無限延長的極端狀況下會建立過多的線程。
參考網址:http://blog.csdn.net/ghsau/article/details/53538303
https://segmentfault.com/a/1190000008394155