Java中怎么創(chuàng)建線程池,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。
10多年的大石橋網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。全網(wǎng)整合營(yíng)銷推廣的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整大石橋建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)從事“大石橋網(wǎng)站設(shè)計(jì)”,“大石橋網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
Executor框架
Executor是一套線程池管理框架,接口里只有一個(gè)方法execute,執(zhí)行Runnable任務(wù)。ExecutorService接口擴(kuò)展了Executor,添加了線程生命周期的管理,提供任務(wù)終止、返回任務(wù)結(jié)果等方法。AbstractExecutorService實(shí)現(xiàn)了ExecutorService,提供例如submit方法的默認(rèn)實(shí)現(xiàn)邏輯。
然后到今天的主題ThreadPoolExecutor,繼承了AbstractExecutorService,提供線程池的具體實(shí)現(xiàn)。
構(gòu)造方法
下面是ThreadPoolExecutor最普通的構(gòu)造函數(shù),最多有七個(gè)參數(shù)。具體代碼不貼了,只是一些參數(shù)校驗(yàn)和設(shè)置的語句。
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {}
corePoolSize是線程池的目標(biāo)大小,即是線程池剛剛創(chuàng)建起來,還沒有任務(wù)要執(zhí)行時(shí)的大小。maximumPoolSize是線程池的最大上限。keepAliveTime是線程的存活時(shí)間,當(dāng)線程池內(nèi)的線程數(shù)量大于corePoolSize,超出存活時(shí)間的空閑線程就會(huì)被回收。unit就不用說了,剩下的三個(gè)參數(shù)看后文的分析。
預(yù)設(shè)的定制線程池
ThreadPoolExecutor預(yù)設(shè)了一些已經(jīng)定制好的線程池,由Executors里的工廠方法創(chuàng)建。下面分析newSingleThreadExecutor、newFixedThreadPool、newCachedThreadPool的創(chuàng)建參數(shù)。
newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}
newFixedThreadPool的corePoolSize和maximumPoolSize都設(shè)置為傳入的固定數(shù)量,keepAliveTim設(shè)置為0。線程池創(chuàng)建后,線程數(shù)量將會(huì)固定不變,適合需要線程很穩(wěn)定的場(chǎng)合。
newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}
newSingleThreadExecutor是線程數(shù)量固定為1的newFixedThreadPool版本,保證池內(nèi)的任務(wù)串行。注意到返回的是FinalizableDelegatedExecutorService,來看看源碼:
static class FinalizableDelegatedExecutorServiceextends DelegatedExecutorService {FinalizableDelegatedExecutorService(ExecutorService executor) {super(executor);}protected void finalize() {super.shutdown();}}
FinalizableDelegatedExecutorService繼承了DelegatedExecutorService,僅僅在gc時(shí)增加關(guān)閉線程池的操作,再來看看DelegatedExecutorService的源碼:
static class DelegatedExecutorService extends AbstractExecutorService {private final ExecutorService e;DelegatedExecutorService(ExecutorService executor) { e = executor; }public void execute(Runnable command) { e.execute(command); }public void shutdown() { e.shutdown(); }public List<Runnable> shutdownNow() { return e.shutdownNow(); }public boolean isShutdown() { return e.isShutdown(); }public boolean isTerminated() { return e.isTerminated(); }//...}
代碼很簡(jiǎn)單,DelegatedExecutorService包裝了ExecutorService,使其只暴露出ExecutorService的方法,因此不能再配置線程池的參數(shù)。本來,線程池創(chuàng)建的參數(shù)是可以調(diào)整的,ThreadPoolExecutor提供了set方法。使用newSingleThreadExecutor目的是生成單線程串行的線程池,如果還能配置線程池大小,那就沒意思了。
Executors還提供了unconfigurableExecutorService方法,將普通線程池包裝成不可配置的線程池。如果不想線程池被不明所以的后人修改,可以調(diào)用這個(gè)方法。
newCachedThreadPool
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}
newCachedThreadPool生成一個(gè)會(huì)緩存的線程池,線程數(shù)量可以從0到Integer.MAX_VALUE,超時(shí)時(shí)間為1分鐘。線程池用起來的效果是:如果有空閑線程,會(huì)復(fù)用線程;如果沒有空閑線程,會(huì)新建線程;如果線程空閑超過1分鐘,將會(huì)被回收。
newScheduledThreadPool
newScheduledThreadPool將會(huì)創(chuàng)建一個(gè)可定時(shí)執(zhí)行任務(wù)的線程池。這個(gè)不打算在本文展開,后續(xù)會(huì)另開文章細(xì)講。
等待隊(duì)列
newCachedThreadPool的線程上限幾乎等同于無限,但系統(tǒng)資源是有限的,任務(wù)的處理速度總有可能比不上任務(wù)的提交速度。因此,可以為ThreadPoolExecutor提供一個(gè)阻塞隊(duì)列來保存因線程不足而等待的Runnable任務(wù),這就是BlockingQueue。
JDK為BlockingQueue提供了幾種實(shí)現(xiàn)方式,常用的有:
ArrayBlockingQueue:數(shù)組結(jié)構(gòu)的阻塞隊(duì)列 LinkedBlockingQueue:鏈表結(jié)構(gòu)的阻塞隊(duì)列 PriorityBlockingQueue:有優(yōu)先級(jí)的阻塞隊(duì)列 SynchronousQueue:不會(huì)存儲(chǔ)元素的阻塞隊(duì)列
newFixedThreadPool和newSingleThreadExecutor在默認(rèn)情況下使用一個(gè)無界的LinkedBlockingQueue。要注意的是,如果任務(wù)一直提交,但線程池又不能及時(shí)處理,等待隊(duì)列將會(huì)無限制地加長(zhǎng),系統(tǒng)資源總會(huì)有消耗殆盡的一刻。所以,推薦使用有界的等待隊(duì)列,避免資源耗盡。但解決一個(gè)問題,又會(huì)帶來新問題:隊(duì)列填滿之后,再來新任務(wù),這個(gè)時(shí)候怎么辦?后文會(huì)介紹如何處理隊(duì)列飽和。
newCachedThreadPool使用的SynchronousQueue十分有趣,看名稱是個(gè)隊(duì)列,但它卻不能存儲(chǔ)元素。要將一個(gè)任務(wù)放進(jìn)隊(duì)列,必須有另一個(gè)線程去接收這個(gè)任務(wù),一個(gè)進(jìn)就有一個(gè)出,隊(duì)列不會(huì)存儲(chǔ)任何東西。因此,SynchronousQueue是一種移交機(jī)制,不能算是隊(duì)列。newCachedThreadPool生成的是一個(gè)沒有上限的線程池,理論上提交多少任務(wù)都可以,使用SynchronousQueue作為等待隊(duì)列正合適。
飽和策略
當(dāng)有界的等待隊(duì)列滿了之后,就需要用到飽和策略去處理,ThreadPoolExecutor的飽和策略通過傳入RejectedExecutionHandler來實(shí)現(xiàn)。如果沒有為構(gòu)造函數(shù)傳入,將會(huì)使用默認(rèn)的defaultHandler。
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();public static class AbortPolicy implements RejectedExecutionHandler {public AbortPolicy() { }public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());}}
AbortPolicy是默認(rèn)的實(shí)現(xiàn),直接拋出一個(gè)RejectedExecutionException異常,讓調(diào)用者自己處理。除此之外,還有幾種飽和策略,來看一下:
public static class DiscardPolicy implements RejectedExecutionHandler {public DiscardPolicy() { }public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {}}
DiscardPolicy的rejectedExecution直接是空方法,什么也不干。如果隊(duì)列滿了,后續(xù)的任務(wù)都拋棄掉。
public static class DiscardOldestPolicy implements RejectedExecutionHandler {public DiscardOldestPolicy() { }public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {e.getQueue().poll();e.execute(r);}}}
DiscardOldestPolicy會(huì)將等待隊(duì)列里最舊的任務(wù)踢走,讓新任務(wù)得以執(zhí)行。
public static class CallerRunsPolicy implements RejectedExecutionHandler {public CallerRunsPolicy() { }public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {r.run();}}}
最后一種飽和策略是CallerRunsPolicy,它既不拋棄新任務(wù),也不拋棄舊任務(wù),而是直接在當(dāng)前線程運(yùn)行這個(gè)任務(wù)。當(dāng)前線程一般就是主線程啊,讓主線程運(yùn)行任務(wù),說不定就阻塞了。如果不是想清楚了整套方案,還是少用這種策略為妙。
ThreadFactory
每當(dāng)線程池需要?jiǎng)?chuàng)建一個(gè)新線程,都是通過線程工廠獲取。如果不為ThreadPoolExecutor設(shè)定一個(gè)線程工廠,就會(huì)使用默認(rèn)的defaultThreadFactory:
public static ThreadFactory defaultThreadFactory() {return new DefaultThreadFactory();}static class DefaultThreadFactory implements ThreadFactory {private static final AtomicInteger poolNumber = new AtomicInteger(1);private final ThreadGroup group;private final AtomicInteger threadNumber = new AtomicInteger(1);private final String namePrefix;DefaultThreadFactory() {SecurityManager s = System.getSecurityManager();group = (s != null) ? s.getThreadGroup() :Thread.currentThread().getThreadGroup();namePrefix = "pool-" +poolNumber.getAndIncrement() +"-thread-";}public Thread newThread(Runnable r) {Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(),0);if (t.isDaemon())t.setDaemon(false);if (t.getPriority() != Thread.NORM_PRIORITY)t.setPriority(Thread.NORM_PRIORITY);return t;}}
平時(shí)打印線程池里線程的name時(shí),會(huì)輸出形如pool-1-thread-1之類的名稱,就是在這里設(shè)置的。這個(gè)默認(rèn)的線程工廠,創(chuàng)建的線程是普通的非守護(hù)線程,如果需要定制,實(shí)現(xiàn)ThreadFactory后傳給ThreadPoolExecutor即可。
不看代碼不總結(jié)不會(huì)知道,光是線程池的創(chuàng)建就可以引出很多學(xué)問。別看平時(shí)創(chuàng)建線程池是一句代碼的事,其實(shí)ThreadPoolExecutor提供了很靈活的定制方法。
關(guān)于Java中怎么創(chuàng)建線程池問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。
本文名稱:Java中怎么創(chuàng)建線程池
鏈接分享:http://www.rwnh.cn/article4/jiphoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營(yíng)銷推廣、網(wǎng)站制作、網(wǎng)站排名、外貿(mào)網(wǎng)站建設(shè)、電子商務(wù)、定制網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)