深入分析java線程池的實現(xiàn)原理-創(chuàng)新互聯(lián)

前言
線程是稀缺資源,如果被無限制的創(chuàng)建,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性,合理的使用線程池對線程進行統(tǒng)一分配、調(diào)優(yōu)和監(jiān)控,有以下好處:
1、降低資源消耗;
2、提高響應速度;
3、提高線程的可管理性。
Java1.5中引入的Executor框架把任務的提交和執(zhí)行進行解耦,只需要定義好任務,然后提交給線程池,而不用關心該任務是如何執(zhí)行、被哪個線程執(zhí)行,以及什么時候執(zhí)行。
demo
深入分析java線程池的實現(xiàn)原理
1、Executors.newFixedThreadPool(10)初始化一個包含10個線程的線程池executor;
2、通過executor.execute方法提交20個任務,每個任務打印當前的線程名;
3、負責執(zhí)行任務的線程的生命周期都由Executor框架進行管理;
ThreadPoolExecutor
Executors是java線程池的工廠類,通過它可以快速初始化一個符合業(yè)務需求的線程池,如Executors.newFixedThreadPool方法可以生成一個擁有固定線程數(shù)的線程池。
深入分析java線程池的實現(xiàn)原理
其本質(zhì)是通過不同的參數(shù)初始化一個ThreadPoolExecutor對象,具體參數(shù)描述如下:
corePoolSize
線程池中的核心線程數(shù),當提交一個任務時,線程池創(chuàng)建一個新線程執(zhí)行任務,直到當前線程數(shù)等于corePoolSize;如果當前線程數(shù)為corePoolSize,繼續(xù)提交的任務被保存到阻塞隊列中,等待被執(zhí)行;如果執(zhí)行了線程池的prestartAllCoreThreads()方法,線程池會提前創(chuàng)建并啟動所有核心線程。
maximumPoolSize
線程池中允許的大線程數(shù)。如果當前阻塞隊列滿了,且繼續(xù)提交任務,則創(chuàng)建新的線程執(zhí)行任務,前提是當前線程數(shù)小于maximumPoolSize;
keepAliveTime
線程空閑時的存活時間,即當線程沒有任務執(zhí)行時,繼續(xù)存活的時間;默認情況下,該參數(shù)只在線程數(shù)大于corePoolSize時才有用;
unit
keepAliveTime的單位;
workQueue
用來保存等待被執(zhí)行的任務的阻塞隊列,且任務必須實現(xiàn)Runable接口,在JDK中提供了如下阻塞隊列:
1、ArrayBlockingQueue:基于數(shù)組結構的有界阻塞隊列,按FIFO排序任務;
2、LinkedBlockingQuene:基于鏈表結構的阻塞隊列,按FIFO排序任務,吞吐量通常要高于ArrayBlockingQuene;
3、SynchronousQuene:一個不存儲元素的阻塞隊列,每個插入操作必須等到另一個線程調(diào)用移除操作,否則插入操作一直處于阻塞狀態(tài),吞吐量通常要高于LinkedBlockingQuene;
4、priorityBlockingQuene:具有優(yōu)先級的×××阻塞隊列;
threadFactory
創(chuàng)建線程的工廠,通過自定義的線程工廠可以給每個新建的線程設置一個具有識別度的線程名。
深入分析java線程池的實現(xiàn)原理
handler
線程池的飽和策略,當阻塞隊列滿了,且沒有空閑的工作線程,如果繼續(xù)提交任務,必須采取一種策略處理該任務,線程池提供了4種策略:
1、AbortPolicy:直接拋出異常,默認策略;
2、CallerRunsPolicy:用調(diào)用者所在的線程來執(zhí)行任務;
3、DiscardOldestPolicy:丟棄阻塞隊列中靠最前的任務,并執(zhí)行當前任務;
4、DiscardPolicy:直接丟棄任務;
當然也可以根據(jù)應用場景實現(xiàn)RejectedExecutionHandler接口,自定義飽和策略,如記錄日志或持久化存儲不能處理的任務。
Exectors
Exectors工廠類提供了線程池的初始化接口,主要有如下幾種:
newFixedThreadPool
深入分析java線程池的實現(xiàn)原理
初始化一個指定線程數(shù)的線程池,其中corePoolSize == maximumPoolSize,使用LinkedBlockingQuene作為阻塞隊列,不過當線程池沒有可執(zhí)行任務時,也不會釋放線程。
newCachedThreadPool
深入分析java線程池的實現(xiàn)原理
1、初始化一個可以緩存線程的線程池,默認緩存60s,線程池的線程數(shù)可達到Integer.MAX_VALUE,即2147483647,內(nèi)部使用SynchronousQueue作為阻塞隊列;
2、和newFixedThreadPool創(chuàng)建的線程池不同,newCachedThreadPool在沒有任務執(zhí)行時,當線程的空閑時間超過keepAliveTime,會自動釋放線程資源,當提交新任務時,如果沒有空閑線程,則創(chuàng)建新線程執(zhí)行任務,會導致一定的系統(tǒng)開銷;
所以,使用該線程池時,一定要注意控制并發(fā)的任務數(shù),否則創(chuàng)建大量的線程可能導致嚴重的性能問題。
newSingleThreadExecutor
深入分析java線程池的實現(xiàn)原理
初始化的線程池中只有一個線程,如果該線程異常結束,會重新創(chuàng)建一個新的線程繼續(xù)執(zhí)行任務,唯一的線程可以保證所提交任務的順序執(zhí)行,內(nèi)部使用LinkedBlockingQueue作為阻塞隊列。
newScheduledThreadPool
深入分析java線程池的實現(xiàn)原理
初始化的線程池可以在指定的時間內(nèi)周期性的執(zhí)行所提交的任務,在實際的業(yè)務場景中可以使用該線程池定期的同步數(shù)據(jù)。
實現(xiàn)原理
除了newScheduledThreadPool的內(nèi)部實現(xiàn)特殊一點之外,其它幾個線程池都是基于ThreadPoolExecutor類實現(xiàn)的。
線程池內(nèi)部狀態(tài)
深入分析java線程池的實現(xiàn)原理
其中AtomicInteger變量ctl的功能非常強大:利用低29位表示線程池中線程數(shù),通過高3位表示線程池的運行狀態(tài):
1、RUNNING:-1 << COUNT_BITS,即高3位為111,該狀態(tài)的線程池會接收新任務,并處理阻塞隊列中的任務;
2、SHUTDOWN: 0 << COUNT_BITS,即高3位為000,該狀態(tài)的線程池不會接收新任務,但會處理阻塞隊列中的任務;
3、STOP : 1 << COUNT_BITS,即高3位為001,該狀態(tài)的線程不會接收新任務,也不會處理阻塞隊列中的任務,而且會中斷正在運行的任務;
4、TIDYING : 2 << COUNT_BITS,即高3位為010;
5、TERMINATED: 3 << COUNT_BITS,即高3位為011;
任務提交
線程池框架提供了兩種方式提交任務,根據(jù)不同的業(yè)務需求選擇不同的方式。
Executor.execute()
深入分析java線程池的實現(xiàn)原理
通過Executor.execute()方法提交的任務,必須實現(xiàn)Runnable接口,該方式提交的任務不能獲取返回值,因此無法判斷任務是否執(zhí)行成功。
ExecutorService.submit()
深入分析java線程池的實現(xiàn)原理
通過ExecutorService.submit()方法提交的任務,可以獲取任務執(zhí)行完的返回值。
任務執(zhí)行
當向線程池中提交一個任務,線程池會如何處理該任務?
execute實現(xiàn)
深入分析java線程池的實現(xiàn)原理
具體的執(zhí)行流程如下:
1、workerCountOf方法根據(jù)ctl的低29位,得到線程池的當前線程數(shù),如果線程數(shù)小于corePoolSize,則執(zhí)行addWorker方法創(chuàng)建新的線程執(zhí)行任務;否則執(zhí)行步驟(2);
2、如果線程池處于RUNNING狀態(tài),且把提交的任務成功放入阻塞隊列中,則執(zhí)行步驟(3),否則執(zhí)行步驟(4);
3、再次檢查線程池的狀態(tài),如果線程池沒有RUNNING,且成功從阻塞隊列中刪除任務,則執(zhí)行reject方法處理任務;
4、執(zhí)行addWorker方法創(chuàng)建新的線程執(zhí)行任務,如果addWoker執(zhí)行失敗,則執(zhí)行reject方法處理任務;
深入分析java線程池的實現(xiàn)原理
addWorker實現(xiàn)
從方法execute的實現(xiàn)可以看出:addWorker主要負責創(chuàng)建新的線程并執(zhí)行任務,代碼實現(xiàn)如下:
深入分析java線程池的實現(xiàn)原理
這只是addWoker方法實現(xiàn)的前半部分:
1、判斷線程池的狀態(tài),如果線程池的狀態(tài)值大于或等SHUTDOWN,則不處理提交的任務,直接返回;
2、通過參數(shù)core判斷當前需要創(chuàng)建的線程是否為核心線程,如果core為true,且當前線程數(shù)小于corePoolSize,則跳出循環(huán),開始創(chuàng)建新的線程,具體實現(xiàn)如下:
深入分析java線程池的實現(xiàn)原理
線程池的工作線程通過Woker類實現(xiàn),在ReentrantLock鎖的保證下,把Woker實例插入到HashSet后,并啟動Woker中的線程,其中Worker類設計如下:
1、繼承了AQS類,可以方便的實現(xiàn)工作線程的中止操作;
2、實現(xiàn)了Runnable接口,可以將自身作為一個任務在工作線程中執(zhí)行;
3、當前提交的任務firstTask作為參數(shù)傳入Worker的構造方法;
深入分析java線程池的實現(xiàn)原理

成都創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務,包含不限于網(wǎng)站建設、成都網(wǎng)站制作、東鄉(xiāng)族網(wǎng)絡推廣、微信平臺小程序開發(fā)、東鄉(xiāng)族網(wǎng)絡營銷、東鄉(xiāng)族企業(yè)策劃、東鄉(xiāng)族品牌公關、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務,您的肯定,是我們大的嘉獎;成都創(chuàng)新互聯(lián)公司為所有大學生創(chuàng)業(yè)者提供東鄉(xiāng)族建站搭建服務,24小時服務熱線:18980820575,官方網(wǎng)址:muchs.cn

從Woker類的構造方法實現(xiàn)可以發(fā)現(xiàn):線程工廠在創(chuàng)建線程thread時,將Woker實例本身this作為參數(shù)傳入,當執(zhí)行start方法啟動線程thread時,本質(zhì)是執(zhí)行了Worker的runWorker方法。
runWorker實現(xiàn)
深入分析java線程池的實現(xiàn)原理
runWorker方法是線程池的核心:
1、線程啟動之后,通過unlock方法釋放鎖,設置AQS的state為0,表示運行中斷;
2、獲取第一個任務firstTask,執(zhí)行任務的run方法,不過在執(zhí)行任務之前,會進行加鎖操作,任務執(zhí)行完會釋放鎖;
3、在執(zhí)行任務的前后,可以根據(jù)業(yè)務場景自定義beforeExecute和afterExecute方法;
4、firstTask執(zhí)行完成之后,通過getTask方法從阻塞隊列中獲取等待的任務,如果隊列中沒有任務,getTask方法會被阻塞并掛起,不會占用cpu資源;
getTask實現(xiàn)
深入分析java線程池的實現(xiàn)原理
整個getTask操作在自旋下完成:
1、workQueue.take:如果阻塞隊列為空,當前線程會被掛起等待;當隊列中有任務加入時,線程被喚醒,take方法返回任務,并執(zhí)行;
2、workQueue.poll:如果在keepAliveTime時間內(nèi),阻塞隊列還是沒有任務,則返回null;
所以,線程池中實現(xiàn)的線程可以一直執(zhí)行由用戶提交的任務。
Future和Callable實現(xiàn)
通過ExecutorService.submit()方法提交的任務,可以獲取任務執(zhí)行完的返回值。
深入分析java線程池的實現(xiàn)原理
在實際業(yè)務場景中,F(xiàn)uture和Callable基本是成對出現(xiàn)的,Callable負責產(chǎn)生結果,F(xiàn)uture負責獲取結果。
1、Callable接口類似于Runnable,只是Runnable沒有返回值。
2、Callable任務除了返回正常結果之外,如果發(fā)生異常,該異常也會被返回,即Future可以拿到異步執(zhí)行任務各種結果;
3、Future.get方法會導致主線程阻塞,直到Callable任務執(zhí)行完成;
submit實現(xiàn)
深入分析java線程池的實現(xiàn)原理
通過submit方法提交的Callable任務會被封裝成了一個FutureTask對象。
FutureTask
深入分析java線程池的實現(xiàn)原理
1、FutureTask在不同階段擁有不同的狀態(tài)state,初始化為NEW;
2、FutureTask類實現(xiàn)了Runnable接口,這樣就可以通過Executor.execute方法提交FutureTask到線程池中等待被執(zhí)行,最終執(zhí)行的是FutureTask的run方法;
FutureTask.get實現(xiàn)
深入分析java線程池的實現(xiàn)原理
內(nèi)部通過awaitDone方法對主線程進行阻塞,具體實現(xiàn)如下:
深入分析java線程池的實現(xiàn)原理
1、如果主線程被中斷,則拋出中斷異常;
2、判斷FutureTask當前的state,如果大于COMPLETING,說明任務已經(jīng)執(zhí)行完成,則直接返回;
3、如果當前state等于COMPLETING,說明任務已經(jīng)執(zhí)行完,這時主線程只需通過yield方法讓出cpu資源,等待state變成NORMAL;
4、通過WaitNode類封裝當前線程,并通過UNSAFE添加到waiters鏈表;
5、最終通過LockSupport的park或parkNanos掛起線程;
FutureTask.run實現(xiàn)
深入分析java線程池的實現(xiàn)原理
FutureTask.run方法是在線程池中被執(zhí)行的,而非主線程
1、通過執(zhí)行Callable任務的call方法;
2、如果call執(zhí)行成功,則通過set方法保存結果;
3、如果call執(zhí)行有異常,則通過setException保存異常;
set
深入分析java線程池的實現(xiàn)原理
setException
深入分析java線程池的實現(xiàn)原理
set和setException方法中,都會通過UnSAFE修改FutureTask的狀態(tài),并執(zhí)行finishCompletion方法通知主線程任務已經(jīng)執(zhí)行完成;
finishCompletion
深入分析java線程池的實現(xiàn)原理
1、執(zhí)行FutureTask類的get方法時,會把主線程封裝成WaitNode節(jié)點并保存在waiters鏈表中;
2、FutureTask任務執(zhí)行完成后,通過UNSAFE設置waiters的值,并通過LockSupport類unpark方法喚醒主線程;

覺得不錯請點贊支持,歡迎留言或進我的個人群855801563領取【架構資料專題目合集90期】、【BATJTMD大廠JAVA面試真題1000+】,本群專用于學習交流技術、分享面試機會,拒絕廣告,我也會在群內(nèi)不定期答題、探討。

創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務器,動態(tài)BGP最優(yōu)骨干路由自動選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡助力業(yè)務部署。公司持有工信部辦法的idc、isp許可證, 機房獨有T級流量清洗系統(tǒng)配攻擊溯源,準確進行流量調(diào)度,確保服務器高可用性。佳節(jié)活動現(xiàn)已開啟,新人活動云服務器買多久送多久。

標題名稱:深入分析java線程池的實現(xiàn)原理-創(chuàng)新互聯(lián)
瀏覽地址:http://muchs.cn/article34/deicse.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供微信小程序、電子商務網(wǎng)站改版、品牌網(wǎng)站建設響應式網(wǎng)站、靜態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

h5響應式網(wǎng)站建設