Executors
要配置線程池是比較復(fù)雜的,在對于線程池的原理不是很清楚的情況下
很有可能配置的線程池不是較優(yōu)的,我們可以參考看一些框架是如何使用線程池的
因此在Executors類里面提供了一些靜態(tài)工廠,生成一些常用的線程池。
線程池可以解決兩個(gè)不同問題:
由于減少了每個(gè)任務(wù)調(diào)用的開銷,它們通??梢栽趫?zhí)行大量異步任務(wù)時(shí)提供增強(qiáng)的性能,
并且還可以提供綁定和管理資源(包括執(zhí)行任務(wù)集時(shí)使用的線程)的方法。
每個(gè) ThreadPoolExecutor 還維護(hù)著一些基本的統(tǒng)計(jì)數(shù)據(jù),如完成的任務(wù)數(shù)。
為了便于跨大量上下文使用,此類提供了很多可調(diào)整的參數(shù)和擴(kuò)展鉤子 (hook)。
但是,強(qiáng)烈建議程序員使用較為方便的 Executors 工廠方法
Executors.newCachedThreadPool()(無界線程池,可以進(jìn)行自動(dòng)線程回收)
Executors.newFixedThreadPool(int)(固定大小線程池)
Executors.newSingleThreadExecutor()(單個(gè)后臺(tái)線程)
它們均為大多數(shù)使用場景預(yù)定義了設(shè)置。否則,在手動(dòng)配置和調(diào)整此類時(shí),使用以下指導(dǎo):
核心和最大池大小 ThreadPoolExecutor 將根據(jù) corePoolSize(參見 getCorePoolSize())
和 maximumPoolSize(參見 getMaximumPoolSize())設(shè)置的邊界自動(dòng)調(diào)整池大小。
當(dāng)新任務(wù)在方法 execute(java.lang.Runnable) 中提交時(shí):
如果運(yùn)行的線程少于 corePoolSize,則創(chuàng)建新線程來處理請求,即使其他輔助線程是空閑的。
如果運(yùn)行的線程多于 corePoolSize 而少于 maximumPoolSize,則僅當(dāng)隊(duì)列滿時(shí)才創(chuàng)建新線程。
如果設(shè)置的 corePoolSize 和 maximumPoolSize 相同,則創(chuàng)建了固定大小的線程池。
如果將 maximumPoolSize 設(shè)置為基本的無界值(如 Integer.MAX_VALUE),則允許池適應(yīng)任意數(shù)量的并發(fā)任務(wù)。
在大多數(shù)情況下,核心和最大池大小僅基于構(gòu)造來設(shè)置,
不過也可以使用 setCorePoolSize(int) 和 setMaximumPoolSize(int) 進(jìn)行動(dòng)態(tài)更改。
按需構(gòu)造 默認(rèn)情況下,即使核心線程最初只是在新任務(wù)到達(dá)時(shí)才創(chuàng)建和啟動(dòng)的,
也可以使用方法 prestartCoreThread() 或 prestartAllCoreThreads() 對其進(jìn)行動(dòng)態(tài)重寫
1、 newSingleThreadExecutor
//核心線程數(shù)和最大線程數(shù)都是1,隊(duì)列為無界隊(duì)列,只有一個(gè)線程存活時(shí)間沒有意義
new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())
創(chuàng)建一個(gè)單線程的線程池。這個(gè)線程池只有一個(gè)線程在工作,也就是相當(dāng)于單線程串行執(zhí)行所有任務(wù)。
如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束,那么會(huì)有一個(gè)新的線程來替代它。
此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。
2、newFixedThreadPool
//核心線程數(shù)等于最大線程數(shù),隊(duì)列為無界隊(duì)列
new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>())
創(chuàng)建固定大小的線程池。每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到線程達(dá)到線程池的最大大小。線程池的大小一旦達(dá)到最大值就會(huì)保持不變,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會(huì)補(bǔ)充一個(gè)新線程。
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"----"+i);
}
}
}
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());

不禁要問 newSingleThreadExecutor不就是newFixedThreadPool(1)嗎?
API文檔中有說明,其實(shí)最好的還是看代碼吧
newSingleThreadExecutor返回的是FinalizableDelegatedExecutorService
被裝飾過的ThreadPoolExecutor,已經(jīng)調(diào)用不到ThreadPoolExecutor的方法了
//newSingleThreadExecutor 不能配置去重新加入線程;
// final ExecutorService single = Executors.newSingleThreadExecutor();
final ExecutorService fixed = Executors.newFixedThreadPool(1);
ThreadPoolExecutor executor = (ThreadPoolExecutor) fixed;
executor.setCorePoolSize(4);
3、 newCachedThreadPool
new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
創(chuàng)建一個(gè)可緩存的線程池。如果線程池的大小超過了處理任務(wù)所需要的線程,
那么就會(huì)回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時(shí),此線程池又可以智能的添加新線程來處理任務(wù)。此線程池不會(huì)對線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。
4、newScheduledThreadPool
創(chuàng)建一個(gè)大小無限的線程池。此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。
submit和execute的區(qū)別
- 接收的參數(shù)不一樣,submit可接收callback,有幾個(gè)重載的方法
- submit有返回值, execute沒有
shutdown和shutdownNow
shutdown()
按過去執(zhí)行已提交任務(wù)的順序發(fā)起一個(gè)有序的關(guān)閉,但是不接受新任務(wù)
如果已經(jīng)關(guān)閉,則調(diào)用沒有其他作用List<Runnable> shutdownNow()
嘗試停止所有的活動(dòng)執(zhí)行任務(wù)、暫停等待任務(wù)的處理,并返回等待執(zhí)行的任務(wù)列表
在從此方法返回的任務(wù)隊(duì)列中排空(移除)這些任務(wù)。 并不保證能夠停止正在處理的活動(dòng)執(zhí)行任務(wù)
但是會(huì)盡力嘗試。 此實(shí)現(xiàn)通過 Thread.interrupt() 取消任務(wù)
所以無法響應(yīng)中斷的任何任務(wù)可能永遠(yuǎn)無法終止