




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第JavaCountDownLatch的源碼硬核解析目錄前言介紹和使用例子概述實現(xiàn)思路源碼解析類結(jié)構(gòu)圖await()實現(xiàn)原理countDown()實現(xiàn)原理
前言
對于并發(fā)執(zhí)行,Java中的CountDownLatch是一個重要的類,簡單理解,CountDownLatch中countdown是倒數(shù)的意思,latch則是門閂的含義。在數(shù)量倒數(shù)到0的時候,打開門閂,一起走,否則都等待在門閂的地方。
為了更好的理解CountDownLatch這個類,本文通過例子和源碼帶領(lǐng)大家深入解析這個類的原理。
介紹和使用
例子
我們先通過一個例子快速理解下CountDownLatch的妙處。
最近LOLS12賽如火如荼舉行,比如我們玩王者榮耀的時候,10個萬玩家登入游戲,每個玩家的網(wǎng)速可能不一樣,只有每個人進(jìn)度條走完,才會一起來到王者峽谷,網(wǎng)速快的要等網(wǎng)速慢的。我們通過例子模擬下這個過程。
@Slf4j(topic="a.CountDownLatchTest")
publicclassCountDownLatchTest{
publicstaticvoidmain(String[]args)throwsInterruptedException{
//創(chuàng)建一個倒時器,默認(rèn)10個數(shù)量
CountDownLatchlatch=newCountDownLatch(10);
ExecutorServiceservice=Executors.newFixedThreadPool(10);
//設(shè)置進(jìn)度數(shù)據(jù)
String[]personProcess=newString[10];
Randomrandom=newRandom();
for(inti=0;ii++){
intfinalJ=i;
service.submit(()-{
//模擬10個人的進(jìn)度條
for(intj=0;j=100;j++){
//模擬網(wǎng)速快慢,隨機生成
try{
Thread.sleep(random.nextInt(100));
}catch(InterruptedExceptione){
e.printStackTrace();
//設(shè)置進(jìn)度數(shù)據(jù)
personProcess[finalJ]=j+"%";
("{}",Arrays.toString(personProcess));
//運行結(jié)束,倒時器-1
latch.countDown();
//打開"閥門"
latch.await();
("王者峽谷到了");
service.shutdown();
運行結(jié)果:
概述
CountDownLatch一般用作多線程倒計時計數(shù)器,強制它們等待其他一組(CountDownLatch的初始化決定)任務(wù)執(zhí)行完成。
構(gòu)造器:
publicCountDownLatch(intcount):設(shè)置倒數(shù)器需要倒數(shù)的數(shù)量
常用API:
publicvoidawait()throwsInterruptedException:調(diào)用await()方法的線程會被掛起,等待直到count值為0再繼續(xù)執(zhí)行。publicbooleanawait(longtimeout,TimeUnitunit)throwsInterruptedException:同await(),若等待timeout時長后,count值還是沒有變?yōu)?,不再等待,繼續(xù)執(zhí)行。時間單位如下常用的毫秒、天、小時、微秒、分鐘、納秒、秒。publicvoidcountDown():count值遞減1publiclonggetCount():獲取當(dāng)前count值
常見使用場景:
一個程序中有N個任務(wù)在執(zhí)行,我們可以創(chuàng)建值為N的CountDownLatch,當(dāng)每個任務(wù)完成后,調(diào)用一下countDown()方法進(jìn)行遞減count值,再在主線程中使用await()方法等待任務(wù)執(zhí)行完成,主線程繼續(xù)執(zhí)行。
實現(xiàn)思路
通過前面的例子和介紹我們知道CountDownLatch的大致使用流程:
創(chuàng)建CountDownLatch并設(shè)置計數(shù)器值。啟動多線程并且調(diào)用CountDownLatch實例的countDown()方法。主線程調(diào)用await()方法,這樣主線程的操作就會在這個方法上阻塞,直到其他線程完成各自的任務(wù),count值為0,停止阻塞,主線程繼續(xù)執(zhí)行。
不妨我們先思考下,它是怎么實現(xiàn)的呢?我們可以問自己幾個問題?
如何做到可以讓主線程阻塞等待在那里?是不是可以調(diào)用LockSupport.park()方法進(jìn)行阻塞。那么什么時候該阻塞呢?我們需要有個變量,比如state,如果state大于0,就阻塞主線程。那么什么時候該喚醒呢,又如何喚醒呢?如果任務(wù)執(zhí)行完成后,我們讓state減去1,也就是調(diào)用countDown()方法,如果發(fā)現(xiàn)state是0,那么就調(diào)用LockSupport.unpark()喚醒此前阻塞的地方,繼續(xù)執(zhí)行。
是不是很熟悉,這就是我們的AQS共享模式的實現(xiàn)原理啊,不了解AQS共享模式的可以參考本篇文章:深入淺出理解Java并發(fā)AQS的共享鎖模式
我們把思路理清楚后,直接看CountDownLatch的源碼。
源碼解析
類結(jié)構(gòu)圖
以上是CountDownLatch的類結(jié)構(gòu)圖,
Sync是CountDownLatch的內(nèi)部類,被成員變量sync持有。Sync繼承了AbstractQueuedSynchronizer,也就是我們大名鼎鼎的AQS。
await()實現(xiàn)原理
1.線程調(diào)用await()會阻塞等待其他線程完成任務(wù)
//CountDownLatch#await
publicvoidawait()throwsInterruptedException{
//調(diào)用AbstractQueuedSynchronizer的acquireSharedInterruptibly方法
sync.acquireSharedInterruptibly(1);
//AbstractQueuedSynchronizer#acquireSharedInterruptibly
publicfinalvoidacquireSharedInterruptibly(intarg)throwsInterruptedException{
//判斷線程是否被打斷,拋出打斷異常
if(Terrupted())
thrownewInterruptedException();
//嘗試獲取共享鎖
//條件成立說明state0,此時線程入隊阻塞等待,等待其他線程獲取共享資源
//條件不成立說明state=0,此時不需要阻塞線程,直接結(jié)束函數(shù)調(diào)用
if(tryAcquireShared(arg)0)
//阻塞當(dāng)前線程的邏輯
doAcquireSharedInterruptibly(arg);
//CountDownLatch.Sync#tryAcquireShared
protectedinttryAcquireShared(intacquires){
return(getState()==0)1:-1;
2.doAcquireSharedInterruptibly()方法是實現(xiàn)線程阻塞的核心邏輯
//AbstractQueuedSynchronizer#doAcquireSharedInterruptibly
privatevoiddoAcquireSharedInterruptibly(intarg)throwsInterruptedException{
//將調(diào)用latch.await()方法的線程包裝成SHARED類型的node加入到AQS的阻塞隊列中
finalNodenode=addWaiter(Node.SHARED);
booleanfailed=true;
try{
for(;;){
//獲取當(dāng)前節(jié)點的前驅(qū)節(jié)點
finalNodep=node.predecessor();
//前驅(qū)節(jié)點時頭節(jié)點就可以嘗試獲取鎖
if(p==head){
//再次嘗試獲取鎖,獲取成功返回1
intr=tryAcquireShared(arg);
if(r=0){
//獲取鎖成功,設(shè)置當(dāng)前節(jié)點為head節(jié)點,并且向后傳播
setHeadAndPropagate(node,r);
p.next=null;//helpGC
failed=false;
return;
//阻塞在這里
if(shouldParkAfterFailedAcquire(p,node)parkAndCheckInterrupt())
thrownewInterruptedException();
}finally{
//阻塞線程被中斷后拋出異常,進(jìn)入取消節(jié)點的邏輯
if(failed)
cancelAcquire(node);
3.parkAndCheckInterrupt()方法中會進(jìn)行阻塞操作
privatefinalbooleanparkAndCheckInterrupt(){
//阻塞線程
LockSupport.park(this);
returnTerrupted();
countDown()實現(xiàn)原理
1.任務(wù)結(jié)束調(diào)用countDown()完成計數(shù)器減一(釋放鎖)的操作
publicvoidcountDown(){
sync.releaseShared(1);
publicfinalbooleanreleaseShared(intarg){
//嘗試釋放共享鎖
if(tryReleaseShared(arg)){
//釋放鎖成功開始喚醒阻塞節(jié)點
doReleaseShared();
returntrue;
returnfalse;
2.調(diào)用tryReleaseShared()方法嘗試釋放鎖,true表示state等于0,去喚醒阻塞線程。
protectedbooleantryReleaseShared(intreleases){
for(;;){
intc=getState();
//條件成立說明前面【已經(jīng)有線程觸發(fā)喚醒操作】了,這里返回false
if(c==0)
returnfalse;
//計數(shù)器減一
intnextc=c-1;
if(compareAndSetState(c,nextc))
//計數(shù)器為0時返回true
returnnextc==0;
3.調(diào)用doReleaseShared()喚醒阻塞的節(jié)點
privatevoiddoReleaseShared(){
for(;;){
Nodeh=head;
//判斷隊列是否是空隊列
if(h!=nullh!=tail){
intws=h.waitStatus;
//頭節(jié)點的狀態(tài)為signal,說明后繼節(jié)點沒有被喚醒過
if(ws==Node.SIGNAL){
//cas設(shè)置頭節(jié)點的狀態(tài)為0,設(shè)置失敗繼續(xù)自旋
if(!compareAndSetWaitStatus(h,Node.SIGNAL,0))
continue;
//喚醒后繼節(jié)點
unparkSuccessor(h);
//如果有其他線程已經(jīng)設(shè)置了頭節(jié)點的狀態(tài),重新設(shè)置為PROPAGATE傳播屬性
elseif(w
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 智能感應(yīng)洗手池節(jié)水系統(tǒng)行業(yè)跨境出海戰(zhàn)略研究報告
- 環(huán)保再生陶瓷餐具企業(yè)制定與實施新質(zhì)生產(chǎn)力戰(zhàn)略研究報告
- 智能水下管道巡檢無人機企業(yè)制定與實施新質(zhì)生產(chǎn)力戰(zhàn)略研究報告
- 智能發(fā)飾紫外線防護帽企業(yè)制定與實施新質(zhì)生產(chǎn)力戰(zhàn)略研究報告
- 智能恒溫電燉鍋企業(yè)制定與實施新質(zhì)生產(chǎn)力戰(zhàn)略研究報告
- 智能快遞包裹分類系統(tǒng)行業(yè)深度調(diào)研及發(fā)展戰(zhàn)略咨詢報告
- 瑪卡精力提升膠囊行業(yè)跨境出海戰(zhàn)略研究報告
- 智能嬰兒床安全監(jiān)測系統(tǒng)行業(yè)跨境出海戰(zhàn)略研究報告
- 電動牙鉆機企業(yè)數(shù)字化轉(zhuǎn)型與智慧升級戰(zhàn)略研究報告
- 玉米家居用品行業(yè)跨境出海戰(zhàn)略研究報告
- 第四屆全國智能制造應(yīng)用技術(shù)技能大賽決賽-儀器儀表制造工(儀器儀表與智能傳感應(yīng)用技術(shù))賽項競賽平臺主要設(shè)備技術(shù)標(biāo)準(zhǔn)
- 夾具設(shè)計-畢業(yè)設(shè)計論文
- 統(tǒng)編版 高中語文 選擇性必修下 第二單元《邊城》
- 白內(nèi)障患者護理教學(xué)查房
- 幼兒園 中班心理健康《我會傾訴》
- 機械租賃保障措施
- 2024-2030年中國病號服行業(yè)市場發(fā)展趨勢與前景展望戰(zhàn)略分析報告
- 洗煤廠安全應(yīng)急預(yù)案
- 2024年天津市武清區(qū)國資產(chǎn)經(jīng)營投資限公司面向社會公開選聘工作人員易考易錯模擬試題(共500題)試卷后附參考答案
- 抖音火花合同模板
- 掬水月在手-古典詩詞與現(xiàn)代人生智慧樹知到期末考試答案章節(jié)答案2024年南開大學(xué)
評論
0/150
提交評論