Java中的CountDownLatch、CyclicBarrier和semaphore實現(xiàn)原理解讀
CountDownLatch
實現(xiàn)原理
CountDownLatch使用構造函數(shù)給AQS中的status賦值,調用await()方法的線程會進行AQS中的等待隊列中,然后調用countDown()方法的線程會對status進行-1,直到status=0時喚醒AQS等待隊列中的線程 使用場景
CountDownLatch中調用await方法線程需要等待所有調用countDown方法的線程執(zhí)行,這就很適合一個業(yè)務需要一些準備條件,等準備條件準備好之后再繼續(xù)執(zhí)行,如果一些復雜的聚合查詢,還有一些類似于廣播消息的功能。
CountDownLatch 構造函數(shù)
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }
這個構造器沒有干別的,就是給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; } }
實際上CountDownLatch就是通過覆蓋tryReleaseShared方法來給state-1,然后返回state是不是等于0了,等于0了就調用doReleaseShared();方法unpark等待隊列中的線程,也就是調用await()方法的線程
await()方法
public voidawait() throws InterruptedException { sync.acquireSharedInterruptibly(1); }
實際上就是通過tryAcquireShared方法判斷state是不是等于0,是的話返回1,不是的話返回-1,當返回-1時就說明countDown方法調用的不到構造器賦值的數(shù)量,則進入AQS等待隊列中,直到countDown方法調用到賦值的數(shù)量被unpark。
CountDownLatch使用的是SHARED節(jié)點,當head的下一個節(jié)點被unpark并獲取到資源時會繼續(xù)喚醒下一個節(jié)點,使得調用await方法的線程看似是同時被喚醒
CyclicBarrier
感覺這個類沒什么使用場景,他有兩個構造器:一個是傳同時運行線程的數(shù)量,一個是傳同時運行線程的數(shù)量和達到規(guī)定數(shù)量后運行的Runable的run方法,實在是沒想到什么場景下會用。
實現(xiàn)原理
在初始化時傳入count值,在每次調用await方法時會count--,當count還大于0時使用當前l(fā)ock的condition的await方法讓當前線程進入到condition的等待隊列中,當count等于0時執(zhí)行構造器中傳入的Runable的run方法,然后再調用condition的signalAll方法喚醒condition等待線程中所有等待的線程,再把count重置為初始值,然后所有線程都繼續(xù)執(zhí)行,看起來就像count數(shù)量的線程一批一批的執(zhí)行,所以實際上cyclicBarrier就是借助了ReentrantLock的condition的await方法讓線程進行等待count數(shù)量的線程就位,然后使用condition的signalAll方法通知所有線程一起執(zhí)行,最后重置count如此往復。
semaphore
semaphore一個典型的用戶場景就是限流,像hystrix就是提供了兩種限流方式:線程池和semaphore。semaphore允許規(guī)定數(shù)量的線程同時運行,但超過后的線程就需要等待前面的某個線程執(zhí)行完后才能執(zhí)行。這就很適合做限流
實現(xiàn)原理
首先回顧一下鎖的實現(xiàn)原理:當state是0時線程可以加鎖成功,state就是代表同一線程的加鎖次數(shù)(讀寫鎖次數(shù)含義會不一樣),不是同一個線程加鎖時只要state不是0就要進入AQS等待隊列中進行park,釋放鎖時state--,直到state等于0后去喚醒AQD等待隊列中的線程
semaphore則有點跟加鎖過程相反:先給state賦值為允許同時運行的線程數(shù),當有線程調用acquire()方法時state--,直到state為0再有線程調用acquire()方法時要進入AQS等待隊列中進行park,直到有之前的線程調用release()方法給state++去喚醒AQS等待隊列中的線程
到此這篇關于Java中的CountDownLatch、CyclicBarrier和semaphore實現(xiàn)原理詳解的文章就介紹到這了,更多相關CountDownLatch、CyclicBarrier和semaphore原理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java如何利用Mybatis進行數(shù)據(jù)權限控制詳解
這篇文章主要介紹了Java如何利用Mybatis進行數(shù)據(jù)權限控制詳解,數(shù)據(jù)權限控制最終的效果是會要求在同一個數(shù)據(jù)請求方法中,根據(jù)不同的權限返回不同的數(shù)據(jù)集,而且無需并且不能由研發(fā)編碼控制。,需要的朋友可以參考下2019-06-06java實現(xiàn)ModbusCRC16校驗的示例代碼
本文介紹了使用Java實現(xiàn)ModbusCRC16校驗,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-11-11SpringBoot配置Redis連接池的實現(xiàn)步驟
本文主要介紹了SpringBoot配置Redis連接池的實現(xiàn)步驟,詳細的講解了連接池的作用、配置方式、連接池參數(shù)說明,具有一定的參考價值,感興趣的可以了解一下2025-03-03Mybatis-Plus之ID自動增長的設置實現(xiàn)
本文主要介紹了Mybatis-Plus之ID自動增長的設置實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07