Java高階應用:執行緒池全面解析
什麼是執行緒池?
很簡單,簡單看名字就知道是裝有執行緒的池子,我們可以把要執行的多執行緒交給執行緒池來處理,和連線池的概念一樣,通過維護一定數量的執行緒池來達到多個執行緒的複用。
執行緒池的好處
我們知道不用執行緒池的話,每個執行緒都要通過new Thread(xxRunnable).start()的方式來建立並執行一個執行緒,執行緒少的話這不會是問題,而真實環境可能會開啟多個執行緒讓系統和程式達到最佳效率,當執行緒數達到一定數量就會耗盡系統的CPU和記憶體資源,也會造成GC頻繁收集和停頓,因為每次建立和銷燬一個執行緒都是要消耗系統資源的,如果為每個任務都建立執行緒這無疑是一個很大的效能瓶頸。所以,執行緒池中的執行緒複用極大節省了系統資源,當執行緒一段時間不再有任務處理時它也會自動銷燬,而不會長駐記憶體。
執行緒池核心類
在java.util.concurrent包中我們能找到執行緒池的定義,其中ThreadPoolExecutor是我們執行緒池核心類,首先看看執行緒池類的主要引數有哪些。
-
corePoolSize:執行緒池的核心大小,也可以理解為最小的執行緒池大小。
-
maximumPoolSize:最大執行緒池大小。
-
keepAliveTime:空餘執行緒存活時間,指的是超過corePoolSize的空餘執行緒達到多長時間才進行銷燬。
-
unit:銷燬時間單位。
-
workQueue:儲存等待執行執行緒的工作佇列。
-
threadFactory:建立執行緒的工廠,一般用預設即可。
-
handler:拒絕策略,當工作佇列、執行緒池全已滿時如何拒絕新任務,預設丟擲異常。
執行緒池工作流程
1、如果執行緒池中的執行緒小於corePoolSize時就會建立新執行緒直接執行任務。
2、如果執行緒池中的執行緒大於corePoolSize時就會暫時把任務儲存到工作佇列workQueue中等待執行。
3、如果工作佇列workQueue也滿時:當執行緒數小於最大執行緒池數maximumPoolSize時就會建立新執行緒來處理,而執行緒數大於等於最大執行緒池數maximumPoolSize時就會執行拒絕策略。
執行緒池分類
Executors是jdk裡面提供的建立執行緒池的工廠類,它預設提供了4種常用的執行緒池應用,而不必我們去重複構造。
-
newFixedThreadPool
固定執行緒池,核心執行緒數和最大執行緒數固定相等,而空閒存活時間為0毫秒,說明此引數也無意義,工作佇列為最大為Integer.MAX_VALUE大小的阻塞佇列。當執行任務時,如果執行緒都很忙,就會丟到工作佇列等有空閒執行緒時再執行,佇列滿就執行預設的拒絕策略。
-
newCachedThreadPool
帶緩衝執行緒池,從構造看核心執行緒數為0,最大執行緒數為Integer最大值大小,超過0個的空閒執行緒在60秒後銷燬,SynchronousQueue這是一個直接提交的佇列,意味著每個新任務都會有執行緒來執行,如果執行緒池有可用執行緒則執行任務,沒有的話就建立一個來執行,執行緒池中的執行緒數不確定,一般建議執行速度較快較小的執行緒,不然這個最大執行緒池邊界過大容易造成記憶體溢位。
-
newSingleThreadExecutor
單執行緒執行緒池,核心執行緒數和最大執行緒數均為1,空閒執行緒存活0毫秒同樣無意思,意味著每次只執行一個執行緒,多餘的先儲存到工作佇列,一個一個執行,保證了執行緒的順序執行。
-
newScheduledThreadPool
排程執行緒池,即按一定的週期執行任務,即定時任務,對ThreadPoolExecutor進行了包裝而已。
拒絕策略
-
AbortPolicy
簡單粗暴,直接丟擲拒絕異常,這也是預設的拒絕策略。
-
CallerRunsPolicy
如果執行緒池未關閉,則會在呼叫者執行緒中直接執行新任務,這會導致主執行緒提交執行緒效能變慢。
-
DiscardPolicy
從方法看沒做任務操作,即表示不處理新任務,即丟棄。
-
DiscardOldestPolicy
拋棄最老的任務,就是從佇列取出最老的任務然後放入新的任務進行執行。
如何提交執行緒
如可以先隨便定義一個固定大小的執行緒池
ExecutorService es = Executors.newFixedThreadPool(3);
提交一個執行緒
es.submit(xxRunnble);
es.execute(xxRunnble);
submit和execute分別有什麼區別呢?
execute沒有返回值,如果不需要知道執行緒的結果就使用execute方法,效能會好很多。
submit返回一個Future物件,如果想知道執行緒結果就使用submit提交,而且它能在主執行緒中通過Future的get方法捕獲執行緒中的異常。
如何關閉執行緒池
es.shutdown();
不再接受新的任務,之前提交的任務等執行結束再關閉執行緒池。
es.shutdownNow();
不再接受新的任務,試圖停止池中的任務再關閉執行緒池,返回所有未處理的執行緒list列表。