1、概述 java
一、ThreadPoolExecutor做爲java.util.concurrent包對外提供基礎實現,之內部線程池的形式對外提供管理任務執行,線程調度,線程池管理等等服務;
二、Executors方法提供的線程服務,都是經過參數設置來實現不一樣的線程池機制。
三、先來了解其線程池管理的機制,有助於正確使用,避免錯誤使用致使嚴重故障。同時能夠根據本身的需求實現本身的線程池 數組
2、核心構造方法講解 異步
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) 線程
構造方法參數講解 code
參數名 | 做用 |
corePoolSize | 核心線程池大小 |
maximumPoolSize | 最大線程池大小 |
keepAliveTime | 線程池中超過corePoolSize數目的空閒線程最大存活時間;能夠allowCoreThreadTimeOut(true)使得核心線程有效時間 |
TimeUnit | keepAliveTime時間單位 |
workQueue | 阻塞任務隊列 |
threadFactory | 新建線程工廠 |
handler | 當提交任務數超過maximumPoolSize+workQueue之和時,任務會交給RejectedExecutionHandler來處理 |
重點講解:
其中比較容易讓人誤解的是:corePoolSize,maximumPoolSize,workQueue之間關係。
1.當線程池小於corePoolSize時,新提交任務將建立一個新線程執行任務,即便此時線程池中存在空閒線程。
2.當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行
3.當workQueue已滿,且maximumPoolSize>corePoolSize時,新提交任務會建立新線程執行任務
4.當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理
5.當線程池中超過corePoolSize線程,空閒時間達到keepAliveTime時,關閉空閒線程
6.當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閒時間達到keepAliveTime也將關閉 排序
線程管理機制圖示:
隊列
workQueue 阻塞任務隊列it
handler 拒絕策略,當線程池與workQueue隊列都滿了的狀況下,對新加任務採起的策略。io
RejectedExecutionException
異常。默認值。3、Executors提供的線程池配置方案
一、構造一個固定線程數目的線程池,配置的corePoolSize與maximumPoolSize大小相同,同時使用了一個無界LinkedBlockingQueue存放阻塞任務,所以多餘的任務將存在再阻塞隊列,不會由RejectedExecutionHandler處理 table
public static ExecutorService newFixedThreadPool(int nThreads)
二、構造一個緩衝功能的線程池,配置corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,以及一個無容量的阻塞隊列 SynchronousQueue,所以任務提交以後,將會建立新的線程執行;線程空閒超過60s將會銷燬
public static ExecutorService newCachedThreadPool()
三、構造一個只支持一個線程的線程池,配置corePoolSize=maximumPoolSize=1,無界阻塞隊列LinkedBlockingQueue;保證任務由一個線程串行執行
public static ExecutorService newSingleThreadExecutor()
四、構造有定時功能的線程池,配置corePoolSize,無界延遲阻塞隊列DelayedWorkQueue;有意思的是:maximumPoolSize=Integer.MAX_VALUE,因爲DelayedWorkQueue是無界隊列,因此這個值是沒有意義的
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
總結:
一、用ThreadPoolExecutor自定義線程池,看線程是的用途,若是任務量不大,能夠用無界隊列,若是任務量很是大,要用有界隊列,防止OOM 二、若是任務量很大,還要求每一個任務都處理成功,要對提交的任務進行阻塞提交,重寫拒絕機制,改成阻塞提交。保證不拋棄一個任務 三、最大線程數通常設爲2N+1最好,N是CPU核數 四、核心線程數,看應用,若是是任務,一天跑一次,設置爲0,合適,由於跑完就停掉了,若是是經常使用線程池,看任務量,是保留一個核心仍是幾個核心線程數 五、若是要獲取任務執行結果,用CompletionService,可是注意,獲取任務的結果的要從新開一個線程獲取,若是在主線程獲取,就要等任務都提交後才獲取,就會阻塞大量任務結果,隊列過大OOM,因此最好異步開個線程獲取結果