建立=>銷燬=>建立
對系統對開銷很大,使用線程池能夠避免重複的開銷一說到線程池天然就會想到池化技術。java
其實所謂池化技術,就是把一些可以複用的東西放到池中,避免重複建立、銷燬的開銷,從而極大提升性能。併發
常見池化技術的例如:性能
JDK 1.5 推出了三大API用來建立線程:線程
Executors.newCachedThreadPool()
:無限線程池(最大21億)Executors.newFixedThreadPool(nThreads)
:固定大小的線程池Executors.newSingleThreadExecutor()
:單個線程的線程池這三個API的底層其實都是由同一個類實現的:ThreadPoolExecutor
類code
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
ThreadPoolExecutor
類ThreadPoolExecutor
類主要有如下七個參數:對象
int corePoolSize
: 核心線程池大小int maximumPoolSize
: 最大核心線程池大小long keepAliveTime
: 線程空閒後的存活時間TimeUnit unit
: 超時單位BlockingQueue<Runnable> workQueue
: 阻塞隊列ThreadFactory threadFactory
: 線程工廠:建立線程的,通常默認RejectedExecutionHandler handle
: 拒絕策略拒絕策略就是當隊列滿時,線程如何去處理新來的任務。繼承
Java內置了四種拒絕策略:接口
ThreadPoolExecutor.CallerRunsPolicy()
隊列
ThreadPoolExecutor.AbortPolicy()
內存
ThreadPoolExecutor.DiscardPolicy()
ThreadPoolExecutor.DiscardOldestPolicy()
功能:只要線程池沒有關閉,就由提交任務的當前線程處理。
使用場景:通常在不容許失敗、對性能要求不高、併發量較小的場景下使用。
功能:當觸發拒絕策略時,直接拋出拒絕執行的異常
使用場景:ThreadPoolExecutor
中默認的策略就是AbortPolicy
,因爲ExecutorService
接口的系列ThreadPoolExecutor
都沒有顯示的設置拒絕策略,因此默認的都是這個。
功能:直接丟棄這個任務,不觸發任何動做
使用場景:提交的任務可有可無,通常用的少。
功能:彈出隊列頭部的元素,而後嘗試執行,至關於排隊的時候把第一我的打死,而後本身代替
使用場景:發佈消息、修改消息相似場景。當老消息還未執行,此時新的消息又來了,這時未執行的消息的版本比如今提交的消息版本要低就能夠被丟棄了。
RUNNING
天然是運行狀態,指能夠接受任務執行隊列裏的任務SHUTDOWN
指調用了 shutdown()
方法,再也不接受新任務了,可是隊列裏的任務得執行完畢。STOP
指調用了 shutdownNow()
方法,再也不接受新任務,同時拋棄阻塞隊列裏的全部任務並中斷全部正在執行任務。TIDYING
全部任務都執行完畢,在調用 shutdown()/shutdownNow()
中都會嘗試更新爲這個狀態。TERMINATED
終止狀態,當執行 terminated()
後會更新爲這個狀態。提交一個任務到線程池中,線程池的處理流程以下:
判斷線程池裏的核心線程是否都在執行任務
線程池判斷工做隊列是否已滿
判斷線程池裏的全部線程是否都處於工做狀態
不過最好不要使用Executors
來建立線程,緣由以下(參考自——阿里巴巴Java開發手冊):
FixedThreadPool
和 SingleThreadPool
: 容許的請求隊列長度爲 Integer.MAX_VALUE,可能會堆積大量的請求,從而致使 OOMCachedThreadPool
: 容許的建立線程數量爲 Integer.MAX_VALUE,可能會建立大量的線程,從而致使 OOM推薦使用ThreadPoolExecutor
類自行建立
// 自定義線程池 ExecutorService threadPool = new ThreadPoolExecutor( 2, Runtime.getRuntime().availableProcessors(),//CPU的核心數,適合CPU密集型任務 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
線程池不是越大越好,要根據任務類型合理進行配置
有兩個方法能夠執行任務execute
和submit
execute
提交沒有返回值,不能判斷是否執行成功。submit
會返回一個Future
對象,經過Future
的get()
方法來獲取返回值。區別:
execute
提交的方式只能提交一個Runnable的對象submit
有三種submit
有返回值,而execute
沒有submit
方便Exception
處理execute
是Executor
接口中惟必定義的方法submit
是ExecutorService
(該接口繼承Executor
)中定義的方法線程池使用完畢,須要對其進行關閉,有兩種方法
shutdown()
:再也不繼續接收新的任務,執行完成已有任務後關閉
shutdownNow()
:直接關閉,若果有任務嘗試中止