JAVA線程池
- 爲什麼會有線程池
- JAVA線程與系統線程的映射方式
- 多對一映射,多個線程被認爲一個系統核心線程,由系統調度,這多個線程在jvm內部進行調度,避免使用系統資源進行調度,快速而又安全。
-
- 一對一映射,在cpu多核時代,上面的模式顯然只能同時使用一個cpu核心,於是出現了一個java線程對應一個系統核心線程的方案。這樣可以發揮多核的作用,不同線程運行在不同的核心上,但缺點是由系統管理線程,開銷太大。
- 線程的代價
- 核心線程的消耗過大。默認一個線程棧1M內存,1024個就是1G了。
- 創建一個核心線程消耗很大,需要分配內存,列入調度等。
- 核心線程的數量越多,操作系統將會花費更多時間去理清線程之間的關係。
- java線程池的誕生
- 爲了緩解不斷重複的創建和銷燬線程,以及可能出現的數量巨大的線程,java創造了線程池的解決方案。
- JAVA線程池
- 核心線程數:java線程池保有的最小線程數量。
- 任務隊列:排隊等待解決的任務。
- 最大線程數量:當隊伍排滿後,允許創建臨時的線程來解決任務。
- 臨時線程過期時間:臨時線程閒置一定時間後,將被銷燬。
- 拒絕策略:當隊列已滿,線程池已滿時,採用什麼樣的策略。
- 線程池的工作流程
- 如果線程池中的線程數量小於核心線程數,會直接創建新的線程。
- 如果線程池中的線程數量大於核心線程數,會將線程中的任務存儲到任務隊列中去。
- 當隊列排滿後,且線程數小於最大線程數量,就會創建新的線程;如果線程數大於等於最大線程數量,就會採用拒絕策略。
- 拒絕策略
- AbortPolicy
簡單粗暴,直接拋出拒絕異常,這也是默認的拒絕策略。 - CallerRunsPolicy
如果線程池未關閉,則會在調用者線程中直接執行新任務,這會導致主線程提交線程性能變慢。 - DiscardPolicy
從方法看沒做任務操作,即表示不處理新任務,即丟棄。 - DiscardOldestPolicy
拋棄最老的任務,就是從隊列取出最老的任務然後放入新的任務進行執行。
- 創建線程池
- 線程池分類,類Executors,是java創建線程池的工廠類,提供了4種線程池。
- newFixedThreadPool 固定線程池,核心線程數和最大線程數相等。
- newCachedThreadPool 緩衝線程池,核心線程數爲0,所有線程都是臨時線程,超過空閒時間會銷燬。
- newSingleThreadExecutor 單線程線程池,核心線程數和最大線程數都爲1。
- newScheduledThreadPool 調度線程池,即按一定的週期執行任務,即定時任務。
- 線程池分類,類Executors,是java創建線程池的工廠類,提供了4種線程池。
但是使用Executors提供的方法創建的線程池,使用的默認任務隊列是無界的,這樣有可能因爲隊列太長而導致內存溢出。
因此最好的的創建線程池的方法是直接使用線程池的構造函數來實例化線程池,創建的過程中傳入一個有界的隊列,就可以有效避免以上問題了。
- 線程池任務提交
- Submit 返回一個Future對象。
- Execute 無返回值。
- 關閉線程池
- Shutdown:不再接受新任務,任務全部完成結束
- shutdownNow:不再接受新的任務,試圖停止池中的任務再關閉線程池,返回所有未處理的線程list列表