Java中的ThreadPoolExecutor線程池原理細(xì)節(jié)解析
一、什么是ThreadPoolExecutor
ThreadPoolExecutor是一個(gè)線程池,最多可使用7個(gè)參數(shù)來控制線程池的生成。 使用線程池可以避免創(chuàng)建和銷毀線程的資源損耗,提高響應(yīng)速度,并且可以管理線程池中線程的數(shù)量和狀態(tài)等等。 阿里巴巴手冊中也推薦使用該線程池,因?yàn)镋xecutors創(chuàng)建緩存線程池時(shí),最大線程數(shù)是Integer.MAX_VALUE,可能導(dǎo)致堆棧溢出。而且使用ThreadPoolExecutor創(chuàng)建線程池可以讓開發(fā)者更好理解線程池原理。
二、使用線程池的優(yōu)點(diǎn)
1.減少系統(tǒng)資源消耗
無須重復(fù)創(chuàng)建和銷毀線程,減少了線程創(chuàng)建和銷毀造成的資源消耗。
2.提高響應(yīng)速度
創(chuàng)建好的線程會(huì)駐留在線程池中,無需創(chuàng)建新線程執(zhí)行任務(wù),因而提高了響應(yīng)速度。
3.提高了線程的可管理性。
線程池可以控制線程的數(shù)量,可以選擇拒絕策略,可以監(jiān)控和管理線程的狀態(tài),控制并發(fā)量等等。 這些都是自己創(chuàng)建線程難以做到的。
三、線程池原理
3.1 線程池的7個(gè)參數(shù)
1)corePoolSize 核心線程數(shù)
線程池常駐線程數(shù)量
2)maximumPoolSize 最大線程數(shù)
最大可存在的線程數(shù)量
3)keepAliveTime 非核心線程的存活時(shí)間
非核心線程空閑時(shí),可以停留的時(shí)間
4)unit 存活時(shí)間的單位
非核心線程空閑時(shí),可以停留的時(shí)間的單位
5)workQueue 阻塞隊(duì)列
線程都在使用中時(shí),可以將任務(wù)保存在阻塞隊(duì)列中,可以設(shè)置隊(duì)列的長度。
6)threadFactory 線程創(chuàng)建工廠
可以選擇創(chuàng)建線程的工廠
7)handler 拒絕策略
當(dāng)線程池?zé)o法存放更多任務(wù)時(shí),處理這些過多的任務(wù)的策略
3.2 線程池執(zhí)行任務(wù)的流程
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); //判斷工作線程數(shù)是否小于核心線程數(shù) if (workerCountOf(c) < corePoolSize) { //是,創(chuàng)建一個(gè)新線程 if (addWorker(command, true)) return; c = ctl.get(); } //否,將任務(wù)嘗試添加到阻塞隊(duì)列中,如果隊(duì)列滿了則會(huì)添加失敗。 if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); //判斷線程池狀態(tài)是否在運(yùn)行中,不在運(yùn)行中時(shí),刪除該任務(wù) if (! isRunning(recheck) && remove(command)) //不在運(yùn)行中時(shí),執(zhí)行拒絕策略 reject(command); //判斷工作線程數(shù)是否為0 else if (workerCountOf(recheck) == 0) //為0的場合,嘗試創(chuàng)建新線程 addWorker(null, false); } //添加失敗的場合,嘗試創(chuàng)建一個(gè)新線程 else if (!addWorker(command, false)) //如果添加失敗,執(zhí)行拒絕策略 reject(command); }
- 當(dāng)執(zhí)行一個(gè)任務(wù)時(shí),首先會(huì)判斷工作線程數(shù)是否小于核心線程數(shù)。
- 如果小于核心線程數(shù),則創(chuàng)建一個(gè)新線程來執(zhí)行該任務(wù)。執(zhí)行完畢。
- 如果大于核心線程數(shù),則嘗試將任務(wù)放入阻塞隊(duì)列中。
- 如果成功放入阻塞隊(duì)列,待有空閑的線程時(shí),空閑線程會(huì)從阻塞隊(duì)列中獲取任務(wù)并執(zhí)行。執(zhí)行完畢。
- 如果放入失敗,表示阻塞隊(duì)列已滿,此時(shí)會(huì)嘗試創(chuàng)建一個(gè)新線程來執(zhí)行該任務(wù)。
- 如果當(dāng)前線程數(shù)小于最大線程數(shù),則會(huì)創(chuàng)建新線程來執(zhí)行該任務(wù)。執(zhí)行完畢。
- 如果工作線程數(shù)等于最大線程數(shù),則不會(huì)創(chuàng)建新線程,嘗試創(chuàng)建失敗。此時(shí)會(huì)執(zhí)行拒絕策略。執(zhí)行完畢。
四、Executors提供的常用線程池
4.1 Executors.newFixedThreadPool
一個(gè)固定數(shù)量的線程池,可以通過傳入的參數(shù)int nThreads來控制線程池的線程數(shù)量。(核心線程數(shù)和最大線程數(shù)相同)
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
4.2 Executors.newSingleThreadExecutor
一個(gè)線程數(shù)只有1的線程池。可以保證任務(wù)的順序執(zhí)行。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
4.3 Executors.newCachedThreadPool
緩存線程池,新創(chuàng)建的線程會(huì)在該線程池中緩存60秒??梢蕴岣叨唐诋惒饺蝿?wù)的性能。 注意,最大線程數(shù)是Integer.MAX_VALUE,高并發(fā)的場合下,可能會(huì)創(chuàng)建大量線程。
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
4.4 Executors.newScheduledThreadPool
定時(shí)任務(wù)線程池,使用該線程池可以定時(shí)執(zhí)行任務(wù)。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); }
到此這篇關(guān)于Java中的ThreadPoolExecutor線程池原理細(xì)節(jié)解析的文章就介紹到這了,更多相關(guān)ThreadPoolExecutor線程池原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java取出list中某幾個(gè)屬性組成一個(gè)新集合的幾種方式
在Java開發(fā)中經(jīng)常需要對List中的對象進(jìn)行一些操作,例如對某個(gè)字段進(jìn)行過濾、排序等,這篇文章主要給大家介紹了關(guān)于java取出list中某幾個(gè)屬性組成一個(gè)新集合的幾種方式,需要的朋友可以參考下2024-03-03MyBatis-Flex實(shí)現(xiàn)多表聯(lián)查(自動(dòng)映射)
我們可以輕松的使用 Mybaits-Flex 鏈接任何數(shù)據(jù)庫,本文主要介紹了MyBatis-Flex實(shí)現(xiàn)多表聯(lián)查(自動(dòng)映射),具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06使用lombok的@Data會(huì)導(dǎo)致棧溢出StackOverflowError問題
這篇文章主要介紹了使用lombok的@Data會(huì)導(dǎo)致棧溢出StackOverflowError問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Java實(shí)現(xiàn)自定義自旋鎖代碼實(shí)例
這篇文章主要介紹了Java實(shí)現(xiàn)自定義自旋鎖代碼實(shí)例,Java自旋鎖是一種線程同步機(jī)制,它允許線程在獲取鎖時(shí)不立即阻塞,而是通過循環(huán)不斷嘗試獲取鎖,直到成功獲取為止,自旋鎖適用于鎖競爭激烈但持有鎖的時(shí)間很短的情況,需要的朋友可以參考下2023-10-10Java中數(shù)據(jù)轉(zhuǎn)換及字符串的“+”操作方法
本文主要介紹了Java中的數(shù)據(jù)類型轉(zhuǎn)換,包括隱式轉(zhuǎn)換和強(qiáng)制轉(zhuǎn)換,隱式轉(zhuǎn)換通常用于將范圍較小的數(shù)據(jù)類型轉(zhuǎn)換為范圍較大的數(shù)據(jù)類型,而強(qiáng)制轉(zhuǎn)換則是將范圍較大的數(shù)據(jù)類型轉(zhuǎn)換為范圍較小的數(shù)據(jù)類型,本文介紹Java中數(shù)據(jù)轉(zhuǎn)換以及字符串的“+”操作,感興趣的朋友一起看看吧2024-10-10