Java中的CountDownLatch、CyclicBarrier和semaphore實(shí)現(xiàn)原理解讀
CountDownLatch
實(shí)現(xiàn)原理
CountDownLatch使用構(gòu)造函數(shù)給AQS中的status賦值,調(diào)用await()方法的線(xiàn)程會(huì)進(jìn)行AQS中的等待隊(duì)列中,然后調(diào)用countDown()方法的線(xiàn)程會(huì)對(duì)status進(jìn)行-1,直到status=0時(shí)喚醒AQS等待隊(duì)列中的線(xiàn)程 使用場(chǎng)景
CountDownLatch中調(diào)用await方法線(xiàn)程需要等待所有調(diào)用countDown方法的線(xiàn)程執(zhí)行,這就很適合一個(gè)業(yè)務(wù)需要一些準(zhǔn)備條件,等準(zhǔn)備條件準(zhǔn)備好之后再繼續(xù)執(zhí)行,如果一些復(fù)雜的聚合查詢(xún),還有一些類(lèi)似于廣播消息的功能。
CountDownLatch 構(gòu)造函數(shù)
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}這個(gè)構(gòu)造器沒(méi)有干別的,就是給state變量賦值。
countDown()方法
public voidcountDown(){
sync.releaseShared(1);
}
public final boolean releaseShared(int arg){
if(tryReleaseShared(arg)){
doReleaseShared();
return true;
}
return false;
}
protected boolean tryReleaseShared(int releases){
// Decrement count; signal when transition to zero
for(;;){
int c =getState();
if(c ==0)
return false;
int nextc = c-1;
if(compareAndSetState(c, nextc))
return nextc ==0;
}
}
實(shí)際上CountDownLatch就是通過(guò)覆蓋tryReleaseShared方法來(lái)給state-1,然后返回state是不是等于0了,等于0了就調(diào)用doReleaseShared();方法unpark等待隊(duì)列中的線(xiàn)程,也就是調(diào)用await()方法的線(xiàn)程
await()方法
public voidawait() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}實(shí)際上就是通過(guò)tryAcquireShared方法判斷state是不是等于0,是的話(huà)返回1,不是的話(huà)返回-1,當(dāng)返回-1時(shí)就說(shuō)明countDown方法調(diào)用的不到構(gòu)造器賦值的數(shù)量,則進(jìn)入AQS等待隊(duì)列中,直到countDown方法調(diào)用到賦值的數(shù)量被unpark。
CountDownLatch使用的是SHARED節(jié)點(diǎn),當(dāng)head的下一個(gè)節(jié)點(diǎn)被unpark并獲取到資源時(shí)會(huì)繼續(xù)喚醒下一個(gè)節(jié)點(diǎn),使得調(diào)用await方法的線(xiàn)程看似是同時(shí)被喚醒
CyclicBarrier
感覺(jué)這個(gè)類(lèi)沒(méi)什么使用場(chǎng)景,他有兩個(gè)構(gòu)造器:一個(gè)是傳同時(shí)運(yùn)行線(xiàn)程的數(shù)量,一個(gè)是傳同時(shí)運(yùn)行線(xiàn)程的數(shù)量和達(dá)到規(guī)定數(shù)量后運(yùn)行的Runable的run方法,實(shí)在是沒(méi)想到什么場(chǎng)景下會(huì)用。
實(shí)現(xiàn)原理
在初始化時(shí)傳入count值,在每次調(diào)用await方法時(shí)會(huì)count--,當(dāng)count還大于0時(shí)使用當(dāng)前l(fā)ock的condition的await方法讓當(dāng)前線(xiàn)程進(jìn)入到condition的等待隊(duì)列中,當(dāng)count等于0時(shí)執(zhí)行構(gòu)造器中傳入的Runable的run方法,然后再調(diào)用condition的signalAll方法喚醒condition等待線(xiàn)程中所有等待的線(xiàn)程,再把count重置為初始值,然后所有線(xiàn)程都繼續(xù)執(zhí)行,看起來(lái)就像count數(shù)量的線(xiàn)程一批一批的執(zhí)行,所以實(shí)際上cyclicBarrier就是借助了ReentrantLock的condition的await方法讓線(xiàn)程進(jìn)行等待count數(shù)量的線(xiàn)程就位,然后使用condition的signalAll方法通知所有線(xiàn)程一起執(zhí)行,最后重置count如此往復(fù)。
semaphore
semaphore一個(gè)典型的用戶(hù)場(chǎng)景就是限流,像hystrix就是提供了兩種限流方式:線(xiàn)程池和semaphore。semaphore允許規(guī)定數(shù)量的線(xiàn)程同時(shí)運(yùn)行,但超過(guò)后的線(xiàn)程就需要等待前面的某個(gè)線(xiàn)程執(zhí)行完后才能執(zhí)行。這就很適合做限流
實(shí)現(xiàn)原理
首先回顧一下鎖的實(shí)現(xiàn)原理:當(dāng)state是0時(shí)線(xiàn)程可以加鎖成功,state就是代表同一線(xiàn)程的加鎖次數(shù)(讀寫(xiě)鎖次數(shù)含義會(huì)不一樣),不是同一個(gè)線(xiàn)程加鎖時(shí)只要state不是0就要進(jìn)入AQS等待隊(duì)列中進(jìn)行park,釋放鎖時(shí)state--,直到state等于0后去喚醒AQD等待隊(duì)列中的線(xiàn)程
semaphore則有點(diǎn)跟加鎖過(guò)程相反:先給state賦值為允許同時(shí)運(yùn)行的線(xiàn)程數(shù),當(dāng)有線(xiàn)程調(diào)用acquire()方法時(shí)state--,直到state為0再有線(xiàn)程調(diào)用acquire()方法時(shí)要進(jìn)入AQS等待隊(duì)列中進(jìn)行park,直到有之前的線(xiàn)程調(diào)用release()方法給state++去喚醒AQS等待隊(duì)列中的線(xiàn)程
到此這篇關(guān)于Java中的CountDownLatch、CyclicBarrier和semaphore實(shí)現(xiàn)原理詳解的文章就介紹到這了,更多相關(guān)CountDownLatch、CyclicBarrier和semaphore原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java如何利用Mybatis進(jìn)行數(shù)據(jù)權(quán)限控制詳解
這篇文章主要介紹了Java如何利用Mybatis進(jìn)行數(shù)據(jù)權(quán)限控制詳解,數(shù)據(jù)權(quán)限控制最終的效果是會(huì)要求在同一個(gè)數(shù)據(jù)請(qǐng)求方法中,根據(jù)不同的權(quán)限返回不同的數(shù)據(jù)集,而且無(wú)需并且不能由研發(fā)編碼控制。,需要的朋友可以參考下2019-06-06
java實(shí)現(xiàn)ModbusCRC16校驗(yàn)的示例代碼
本文介紹了使用Java實(shí)現(xiàn)ModbusCRC16校驗(yàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-11-11
深入理解Java線(xiàn)程池從設(shè)計(jì)思想到源碼解讀
這篇文章主要介紹了深入理解Java線(xiàn)程池從設(shè)計(jì)思想到源碼解讀,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
SpringBoot配置Redis連接池的實(shí)現(xiàn)步驟
本文主要介紹了SpringBoot配置Redis連接池的實(shí)現(xiàn)步驟,詳細(xì)的講解了連接池的作用、配置方式、連接池參數(shù)說(shuō)明,具有一定的參考價(jià)值,感興趣的可以了解一下2025-03-03
Idea創(chuàng)建Jsp項(xiàng)目完整版教程
一直在使用eclipse,對(duì)idea嗤之以鼻,前些日子換成了idea以后覺(jué)得太香了,這篇文章主要給大家介紹了關(guān)于Idea創(chuàng)建Jsp項(xiàng)目的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-04-04
springboot與springmvc基礎(chǔ)入門(mén)講解
本篇文章主要介紹了詳解快速搭建Spring Boot+Spring MVC,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2021-07-07
Mybatis-Plus之ID自動(dòng)增長(zhǎng)的設(shè)置實(shí)現(xiàn)
本文主要介紹了Mybatis-Plus之ID自動(dòng)增長(zhǎng)的設(shè)置實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07

