2017/04/23 于復(fù)興中路裸心社 前言線程是稀缺資源,,如果被無限制的創(chuàng)建,,不僅會(huì)消耗系統(tǒng)資源,還會(huì)降低系統(tǒng)的穩(wěn)定性,,合理的使用線程池對線程進(jìn)行統(tǒng)一分配,、調(diào)優(yōu)和監(jiān)控,有以下好處: Java1.5中引入的Executor框架把任務(wù)的提交和執(zhí)行進(jìn)行解耦,,只需要定義好任務(wù),,然后提交給線程池,而不用關(guān)心該任務(wù)是如何執(zhí)行,、被哪個(gè)線程執(zhí)行,,以及什么時(shí)候執(zhí)行。 demo1,、 ThreadPoolExecutorExecutors是java線程池的工廠類,,通過它可以快速初始化一個(gè)符合業(yè)務(wù)需求的線程池,如 其本質(zhì)是通過不同的參數(shù)初始化一個(gè)ThreadPoolExecutor對象,,具體參數(shù)描述如下: corePoolSize線程池中的核心線程數(shù),,當(dāng)提交一個(gè)任務(wù)時(shí),,線程池創(chuàng)建一個(gè)新線程執(zhí)行任務(wù),直到當(dāng)前線程數(shù)等于corePoolSize,;如果當(dāng)前線程數(shù)為corePoolSize,,繼續(xù)提交的任務(wù)被保存到阻塞隊(duì)列中,等待被執(zhí)行,;如果執(zhí)行了線程池的prestartAllCoreThreads()方法,線程池會(huì)提前創(chuàng)建并啟動(dòng)所有核心線程,。 maximumPoolSize線程池中允許的最大線程數(shù),。如果當(dāng)前阻塞隊(duì)列滿了,,且繼續(xù)提交任務(wù),則創(chuàng)建新的線程執(zhí)行任務(wù),,前提是當(dāng)前線程數(shù)小于maximumPoolSize,; keepAliveTime線程空閑時(shí)的存活時(shí)間,,即當(dāng)線程沒有任務(wù)執(zhí)行時(shí),,繼續(xù)存活的時(shí)間;默認(rèn)情況下,,該參數(shù)只在線程數(shù)大于corePoolSize時(shí)才有用,; unitkeepAliveTime的單位,; workQueue用來保存等待被執(zhí)行的任務(wù)的阻塞隊(duì)列,,且任務(wù)必須實(shí)現(xiàn)Runable接口,,在JDK中提供了如下阻塞隊(duì)列: threadFactory創(chuàng)建線程的工廠,,通過自定義的線程工廠可以給每個(gè)新建的線程設(shè)置一個(gè)具有識(shí)別度的線程名。 handler線程池的飽和策略,,當(dāng)阻塞隊(duì)列滿了,且沒有空閑的工作線程,,如果繼續(xù)提交任務(wù),,必須采取一種策略處理該任務(wù),,線程池提供了4種策略: ExectorsExectors工廠類提供了線程池的初始化接口,主要有如下幾種: newFixedThreadPool初始化一個(gè)指定線程數(shù)的線程池,,其中corePoolSize == maximumPoolSize,,使用LinkedBlockingQuene作為阻塞隊(duì)列,,不過當(dāng)線程池沒有可執(zhí)行任務(wù)時(shí),,也不會(huì)釋放線程,。 newCachedThreadPool1,、初始化一個(gè)可以緩存線程的線程池,,默認(rèn)緩存60s,線程池的線程數(shù)可達(dá)到Integer.MAX_VALUE,,即2147483647,內(nèi)部使用SynchronousQueue作為阻塞隊(duì)列; 所以,,使用該線程池時(shí),一定要注意控制并發(fā)的任務(wù)數(shù),,否則創(chuàng)建大量的線程可能導(dǎo)致嚴(yán)重的性能問題,。 newSingleThreadExecutor初始化的線程池中只有一個(gè)線程,如果該線程異常結(jié)束,,會(huì)重新創(chuàng)建一個(gè)新的線程繼續(xù)執(zhí)行任務(wù),,唯一的線程可以保證所提交任務(wù)的順序執(zhí)行,內(nèi)部使用LinkedBlockingQueue作為阻塞隊(duì)列,。 newScheduledThreadPool初始化的線程池可以在指定的時(shí)間內(nèi)周期性的執(zhí)行所提交的任務(wù),,在實(shí)際的業(yè)務(wù)場景中可以使用該線程池定期的同步數(shù)據(jù)。 實(shí)現(xiàn)原理除了newScheduledThreadPool的內(nèi)部實(shí)現(xiàn)特殊一點(diǎn)之外,,其它幾個(gè)線程池都是基于ThreadPoolExecutor類實(shí)現(xiàn)的,。 線程池內(nèi)部狀態(tài)其中AtomicInteger變量ctl的功能非常強(qiáng)大:利用低29位表示線程池中線程數(shù),通過高3位表示線程池的運(yùn)行狀態(tài): 任務(wù)提交線程池框架提供了兩種方式提交任務(wù),,根據(jù)不同的業(yè)務(wù)需求選擇不同的方式,。 Executor.execute()通過Executor.execute()方法提交的任務(wù),必須實(shí)現(xiàn)Runnable接口,,該方式提交的任務(wù)不能獲取返回值,,因此無法判斷任務(wù)是否執(zhí)行成功。 ExecutorService.submit()通過ExecutorService.submit()方法提交的任務(wù),,可以獲取任務(wù)執(zhí)行完的返回值,。 任務(wù)執(zhí)行當(dāng)向線程池中提交一個(gè)任務(wù),線程池會(huì)如何處理該任務(wù),? execute實(shí)現(xiàn)具體的執(zhí)行流程如下: addWorker實(shí)現(xiàn)從方法execute的實(shí)現(xiàn)可以看出:addWorker主要負(fù)責(zé)創(chuàng)建新的線程并執(zhí)行任務(wù),,代碼實(shí)現(xiàn)如下: 這只是addWoker方法實(shí)現(xiàn)的前半部分: 線程池的工作線程通過Woker類實(shí)現(xiàn),,在ReentrantLock鎖的保證下,,把Woker實(shí)例插入到HashSet后,并啟動(dòng)Woker中的線程,,其中Worker類設(shè)計(jì)如下: 從Woker類的構(gòu)造方法實(shí)現(xiàn)可以發(fā)現(xiàn):線程工廠在創(chuàng)建線程thread時(shí),,將Woker實(shí)例本身this作為參數(shù)傳入,,當(dāng)執(zhí)行start方法啟動(dòng)線程thread時(shí),本質(zhì)是執(zhí)行了Worker的runWorker方法,。 runWorker實(shí)現(xiàn)runWorker方法是線程池的核心: getTask實(shí)現(xiàn)整個(gè)getTask操作在自旋下完成: 所以,,線程池中實(shí)現(xiàn)的線程可以一直執(zhí)行由用戶提交的任務(wù)。 Future和Callable實(shí)現(xiàn)通過ExecutorService.submit()方法提交的任務(wù),,可以獲取任務(wù)執(zhí)行完的返回值,。 在實(shí)際業(yè)務(wù)場景中,F(xiàn)uture和Callable基本是成對出現(xiàn)的,,Callable負(fù)責(zé)產(chǎn)生結(jié)果,,F(xiàn)uture負(fù)責(zé)獲取結(jié)果。 submit實(shí)現(xiàn)通過submit方法提交的Callable任務(wù)會(huì)被封裝成了一個(gè)FutureTask對象。 FutureTask1,、FutureTask在不同階段擁有不同的狀態(tài)state,,初始化為NEW; FutureTask.get實(shí)現(xiàn)內(nèi)部通過awaitDone方法對主線程進(jìn)行阻塞,,具體實(shí)現(xiàn)如下: 1、如果主線程被中斷,,則拋出中斷異常,; FutureTask.run實(shí)現(xiàn)FutureTask.run方法是在線程池中被執(zhí)行的,而非主線程 setsetExceptionset和setException方法中,都會(huì)通過UnSAFE修改FutureTask的狀態(tài),,并執(zhí)行finishCompletion方法通知主線程任務(wù)已經(jīng)執(zhí)行完成,; finishCompletion1,、執(zhí)行FutureTask類的get方法時(shí),會(huì)把主線程封裝成WaitNode節(jié)點(diǎn)并保存在waiters鏈表中,; 我是占小狼 |
|