一開始很猶豫這要不要寫這篇文章,在網上看了不少文章寫的都很不錯,可是秉持着更全更易懂的原則,仍是打算本身整理一篇。也參考了不少的文章博客,但願這篇文章可以真正的幫到你。(同時吐槽下,稀土掘金就不能增長一個分類專區的功能嗎,這樣博客寫多了,很差歸類的)java
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 複製代碼
線程池建立線程的時候,若是當前的線程總個數 < corePoolSize,那麼新建的線程爲核心線程,若是當前線程總個數 >= corePoolSize,那麼新建的線程爲非核心線程。 核心線程默認會一直存活下去,即使是空閒狀態,可是若是設置了allowCoreThreadTimeOut(true)的話,那麼核心線程空閒時間達到keepAliveTime也將關閉。緩存
核心線程數 + 非核心線程數 = 最大線程數量微信
非核心線程在空閒狀態下,超過keepAliveTime時間,就會被回收,若是核心線程設置了allowCoreThreadTimeOut(true)的話,那麼在空閒時,超過keepAliveTime時間,也會被回收。併發
時、分、秒、毫秒等ide
當有任務到來時,會指派給核心線程去執行,等核心線程都被佔用了,那麼再有新的任務,就會加入到隊列中,等隊列滿了,再有任務,就再啓動非核心線程去執行。經常使用的隊列以下spa
SynchronousQueue 使用這個隊列時,當有任務到來的時候,它並不存任務,而是直接將任務丟給線程去執行,若是線程都在被佔用,它就會建立線程去處理這個任務,因此通常使用這個緩存隊列的時候,maximumPoolSize(線程池能容納的最大線程數量)設置到 Integer.MAX_VALUE,否則任務數超過maximumPoolSize限制而建立不了線程。線程
LinkedBlockingQueue 使用這個隊列是,當有任務到來的時候,若是當前的核心線程數 < corePoolSize,它會新建核心線程去執行任務,若是當前核心線程數 >= corePoolSize時,它會將還未被執行的任務存儲起來,等待執行,可是這個隊列,沒有存儲上限,因此尼,這也就形成了,maximumPoolSize(總線程數),永遠不會超過corePoolSize。此隊列按 FIFO(先進先出)原則對任務進行操做。3d
ArrayBlockingQueue 使用這個隊列尼,能夠設置隊列的長度,那麼當任務到來的時候,核心線程數 < corePoolSize時, 則建立核心線程去執行任務,若是核心線程數 >= corePoolSize時,加入到隊列裏面,等待執行,若是隊列也滿了,則新建非核心線程去執行任務。此隊列按 FIFO(先進先出)原則對元素進行操做。可是線程數不能超過總線程數。code
DelayQueue(延時隊列) 任務到來時,首先先加入到隊列中,只有達到了指定的延時時間,纔會執行任務。cdn
用來建立線程池中的線程,用默認的便可。
當任務過多時,即:當前線程數已經達到了最大線程數,緩衝隊列也已經滿了,或者線程池關閉了,那麼再來的任務請求,咱們會拒絕,怎麼拒絕尼?有如下幾個方案:
「當你有了,原配,想再娶個小三時,原配的態度」,默認策略,簡單粗暴,直接拒絕拋異常(RejectedExecutionException)
「原配的太粗暴,無法子,只能把小三的電話,微信都刪掉了,不再來往了」,DiscardPolicy策略就是,直接丟棄,可是不拋異常。若是線程隊列已滿,則後續提交的任務都會被丟棄。
「可是原配看久了,很膩了,算了,人生短短几十年,何須委屈本身,休妻,騰地方,娶小三」,DiscardOldestPolicy策略就是,直接丟棄掉隊伍最前面的任務,再從新提交後面新來的任務。
CallerRunsPolicy
「唉,原配雖然很差看,可是家裏有背景,不敢隨意拋棄,後面的小三仍是哪來的回哪去吧,找個熟人照顧着」,CallerRunsPolicy策略就是不拋棄任務,由調用者運行這個任務,好比主線程啓動了線程池去運行這個任務,如今線程池滿了,那麼這個任務就由主線程進行調用執行了。
總結一下 讓任務到來的時候,會執行如下的流程
明白了嗎?若是你不想本身寫一個線程池,有更簡單的方式,就是系統已經爲咱們定義好了幾個線程池,下面介紹下他們的使用,看看有沒有符合你要求的,。
看下圖
建立一個定長的線程池,可控制線程最大的併發數,超出的部分任務,會在隊列中等待,適用於:已知併發壓力的狀況下,對線程數作限制。實際上就是隻使用核心線程。
private void testFiexdThreadPool() {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
for (int n = 0; n < 10; n++){
final int finalN = n;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+ finalN);
}
});
}
}
複製代碼
結果
建立一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO, LIFO, 優先級)執行。
private void testSingleThreadExecutor(){
ExecutorService threadPool = Executors.newSingleThreadExecutor();
for (int n = 0; n < 10; n++){
final int finalN = n;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+ finalN);
}
});
}
}
複製代碼
結果
建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可回收,則新建線程。
private void testCachedThreadPool(){
ExecutorService threadPool = Executors.newCachedThreadPool();
for (int n = 0; n < 10; n++){
final int finalN = n;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+ finalN);
}
});
}
}
複製代碼
結果
建立一個可按期或者延時執行任務的定長線程池,支持定時及週期性任務執行。
private void testScheduledThreadPool(){
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);
for (int n = 0; n < 10; n++){
final int finalN = n;
threadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+ finalN);
}
}, 3, 2, TimeUnit.SECONDS);
}
}
複製代碼
結果