爲了更好的控制多線程,JDK提供了一套線程框架Executor,幫助開發人員有效的進行線程控制。他們都在,java.util.concurrent包中,是JDK併發包的核心。其中有一個比較重要的類Executor:他扮演着線程工廠的角色,我們通過Executors可以創建具有特定功能的線程池。
Executors創建線程池的方法:
newCachedThreadPool()方法:返回一個可根據實際使用情況調整線程個數的線程池。不限制最大線程數量,若有空閒的線程則執行任務,若無任務則不創建線程,並且每個空閒線程默認會在60秒後自動回收。
newFixedThreadPool()方法:返回一個固定數量的線程池,該方法的線程數始終不變。當有一個任務提交時,若線程池中有線程空閒,則立即執行,若沒有空閒線程,則被暫緩在一個任務隊列中等待有空閒的線程去執行。
newSingleThreadExecutor()方法:創建只有一個線程的線程池。若有空閒線程則立即執行,若沒有,則被暫緩在任務隊列中。
newScheduledThreadPool()方法:該方法返回一個ScheduledExecutorService對象,具有定時器的功能。
自定義線程池:若Executors工廠類無法滿足我們的需求,可以自己去常見自定義線程池,其實Executors工廠類中所有的創建線程池方法均是用ThreadPoolExecutor這個類,這個類可以自定義線程,構造方法如下:
new ThreadPoolExecutor(int corePoolSize, //當前核心線程數(當線程剛new出來時線程池中線程個數)
int maximumPoolSize, //最大線程數
long keepAliveTime, //保持存活的時間(空閒時間)
TimeUnit unit, //空閒時間單位
BlockingQueue<Runnable> workQueue //任務隊列
ThreadFactory threadFactory, //
RejectedExecutionHandler handler //拒絕執行的任務
)
自定義線程池使用詳細:
指定構造方法的隊列是什麼類型的比較關鍵:
使用有界隊列時,若有新的任務需要執行,如果線程池中實際線程數小於corePoolSize,則優先創建線程;若大於corePoolSize則將該任務加入任務隊列中;若隊列已滿,則在線程總數不大於maxPoolSize的前提下創建新的線程;若線程數大於maxPoolSize則執行拒絕策略,或其他自定義方式。
使用無界隊列時:LinkedBlockingQueue。與有界隊列相比,除非系統資源耗盡,否則無界的任務隊列不存在任務入隊失敗的問題。當有新任務到來,系統的線程數小於corePoolSize時,則新建線程執行任務;當達到corePoolSize後就不再增加新的線程。若後續還有新任務到來,而又沒有空閒的線程資源,則任務直接進入任務隊列等待。若任務創建與執行的速度差異很大,無界隊列會保持快速增長,直到耗盡系統內存。
JKD拒絕策略:
AbortPolicy:直接拋出異常系統正常工作
CallerRunPolicy:只要線程池未關閉,該策略直接在調用者線程中,運行當前被丟棄的任務。
DiscardOldestPolicy:丟棄最早的一個任務,嘗試再次提交當前任務。
DiscardPolicy:丟棄無法處理的任務,不給予任何處理。
其實這四種拒絕策略都比較暴力並不推薦。
推薦:如果需要自定義拒絕策略,可以實現RejectedExecutionHandler接口。
關於execute方法和submit方法:
execute方法:沒有返回值,只是執行線程任務。
submit方法:會有一個Future的返回值,該類具有get()方法,當get結果爲null時說明該線程執行完畢。