你還不瞭解線程池原理?趕忙來補一下

1、爲何要用線程池

  1. 下降資源消耗。經過重複利用已建立的線程下降線程建立、銷燬線程形成的消耗。程序員

  2. 提升響應速度。當任務到達時,任務能夠不須要等到線程建立就能當即執行。數組

  3. 提升線程的可管理性。線程是稀缺資源,若是無限制的建立,不只會消耗系統資源,還會下降系統的穩定性,使用線程池能夠進行統一的分配、調優和監控緩存

2、ThreadPoolExecutor線程池類參數詳解

參數 說明
corePoolSize 核心線程數量,線程池維護線程的最少數量
maximumPoolSize 線程池維護線程的最大數量
keepAliveTime 線程池除核心線程外的其餘線程的最長空閒時間,超過該時間的空閒線程會被銷燬
unit keepAliveTime的單位,TimeUnit中的幾個靜態屬性:NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS
workQueue 線程池所使用的任務緩衝隊列
threadFactory 線程工廠,用於建立線程,通常用默認的便可
handler 線程池對拒絕任務的處理策略

當線程池任務處理不過來的時候(何時認爲處理不過來後面描述),能夠經過handler指定的策略進行處理,ThreadPoolExecutor提供了四種策略:併發

  1. ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException異常;也是默認的處理方式。
  2. ThreadPoolExecutor.DiscardPolicy:丟棄任務,可是不拋出異常。
  3. ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,而後從新嘗試執行任務(重複此過程)
  4. ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務

能夠經過實現RejectedExecutionHandler接口自定義處理方式。函數

3、線程池任務執行

1. 添加執行任務

  • submit() 該方法返回一個Future對象,可執行帶返回值的線程;或者執行想隨時能夠取消的線程。Future對象的get()方法獲取返回值。Future對象的cancel(true/false)取消任務,未開始或已完成返回false,參數表示是否中斷執行中的線程
  • execute() 沒有返回值。

2. 線程池任務提交過程

2.1. 若是此時線程池中的數量小於corePoolSize,即便線程池中的線程都處於空閒狀態,也要建立新的線程來處理被添加的任務。線程

2.2. 若是此時線程池中的數量等於corePoolSize,可是緩衝隊列workQueue未滿,那麼任務被放入緩衝隊列。code

2.3. 若是此時線程池中的數量大於等於corePoolSize,緩衝隊列workQueue滿,而且線程池中的數量小於maximumPoolSize,建新的線程來處理被添加的任務。對象

2.4. 若是此時線程池中的數量大於corePoolSize,緩衝隊列workQueue滿,而且線程池中的數量等於maximumPoolSize,那麼經過 handler所指定的策略來處理此任務。接口

2.5. 當線程池中的線程數量大於 corePoolSize時,若是某線程空閒時間超過keepAliveTime,線程將被終止。這樣,線程池能夠動態的調整池中的線程數。隊列

總結即:處理任務判斷的優先級爲 核心線程corePoolSize、任務隊列workQueue、最大線程maximumPoolSize,若是三者都滿了,使用handler處理被拒絕的任務。

注意:

  1. 當workQueue使用的是無界限隊列時,maximumPoolSize參數就變的無心義了,好比new LinkedBlockingQueue(),或者new ArrayBlockingQueue(Integer.MAX_VALUE);
  2. 使用SynchronousQueue隊列時因爲該隊列沒有容量的特性,因此不會對任務進行排隊,若是線程池中沒有空閒線程,會當即建立一個新線程來接收這個任務。maximumPoolSize要設置大一點。
  3. 核心線程和最大線程數量相等時keepAliveTime無做用.

3. 線程池關閉

3.1. shutdown() 不接收新任務,會處理已添加任務 3.2. shutdownNow() 不接受新任務,不處理已添加任務,中斷正在處理的任務

4. 經常使用隊列介紹

4.1. ArrayBlockingQueue: 這是一個由數組實現的容量固定的有界阻塞隊列.

4.2. SynchronousQueue: 沒有容量,不能緩存數據;每一個put必須等待一個take; offer()的時候若是沒有另外一個線程在poll()或者take()的話返回false。

4.3. LinkedBlockingQueue: 這是一個由單鏈表實現的默認無界的阻塞隊列。LinkedBlockingQueue提供了一個可選有界的構造函數,而在未指明容量時,容量默認爲Integer.MAX_VALUE。

隊列操做:

方法 說明
add 增長一個元索; 若是隊列已滿,則拋出一個異常
remove 移除並返回隊列頭部的元素; 若是隊列爲空,則拋出一個異常
offer 添加一個元素並返回true; 若是隊列已滿,則返回false
poll 移除並返回隊列頭部的元素; 若是隊列爲空,則返回null
put 添加一個元素; 若是隊列滿,則阻塞
take 移除並返回隊列頭部的元素; 若是隊列爲空,則阻塞
element 返回隊列頭部的元素; 若是隊列爲空,則拋出一個異常
peek 返回隊列頭部的元素; 若是隊列爲空,則返回null

5. Executors線程工廠類

1. Executors.newCachedThreadPool(); 說明: 建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可回收,則新建線程. 內部實現:new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<runnable>());</runnable>

2. Executors.newFixedThreadPool(int); 說明: 建立一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。 內部實現:new ThreadPoolExecutor(nThreads, nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<runnable>());</runnable>

3. Executors.newSingleThreadExecutor(); 說明:建立一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照順序執行。 內部實現:new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<runnable>())</runnable>

4. Executors.newScheduledThreadPool(int); 說明:建立一個定長線程池,支持定時及週期性任務執行。 內部實現:new ScheduledThreadPoolExecutor(corePoolSize)

【附】阿里巴巴Java開發手冊中對線程池的使用規範

  1. 【強制】建立線程或線程池時請指定有意義的線程名稱,方便出錯時回溯。 正例:
public class TimerTaskThread extends Thread {
    public TimerTaskThread(){
        super.setName("TimerTaskThread"); 
        ...
    }
}
  1. 【強制】線程資源必須經過線程池提供,不容許在應用中自行顯式建立線程。 說明: 使用線程池的好處是減小在建立和銷燬線程上所花的時間以及系統資源的開銷,解決資 源不足的問題。若是不使用線程池,有可能形成系統建立大量同類線程而致使消耗完內存或者 「過分切換」的問題。

  2. 【強制】線程池不容許使用 Executors 去建立,而是經過 ThreadPoolExecutor 的方式,這樣 的處理方式讓寫的同窗更加明確線程池的運行規則,規避資源耗盡的風險。

說明: Executors 返回的線程池對象的弊端以下: 1) FixedThreadPool 和 SingleThreadPool: 容許的請求隊列長度爲 Integer.MAX_VALUE,可能會堆積大量的請求,從而致使 OOM。 2) CachedThreadPool 和 ScheduledThreadPool: 容許的建立線程數量爲 Integer.MAX_VALUE, 可能會建立大量的線程,從而致使 OOM。

6. 總結

ThreadPoolExecutor經過幾個核心參數來定義不一樣類型的線程池,適用於不一樣的使用場景;其中在任務提交時,會依次判斷corePoolSize, workQueque, 及maximumPoolSize,不一樣的狀態不一樣的處理。技術領域水太深,若是不是平常使用,基本一段時間後某些知識點就忘的差很少了,所以階段性地回顧與總結,對夯實本身的技術基礎頗有必要。

點關注,不迷路,這是一個程序員都想要關注的公衆號

相關文章
相關標籤/搜索