最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談java并發(fā)之計數(shù)器CountDownLatch

 更新時間:2019年06月06日 11:28:53   作者:exposure  
CountDownLatch是通過一個計數(shù)器來實現(xiàn)的,當我們在new 一個CountDownLatch對象的時候需要帶入該計數(shù)器值,該值就表示了線程的數(shù)量。下面我們來深入了解一下吧

CountDownLatch簡介

CountDownLatch顧名思義,count + down + latch = 計數(shù) + 減 + 門閂(這么拆分也是便于記憶=_=) 可以理解這個東西就是個計數(shù)器,只能減不能加,同時它還有個門閂的作用,當計數(shù)器不為0時,門閂是鎖著的;當計數(shù)器減到0時,門閂就打開了。

如果你感到懵比的話,可以類比考生考試交卷,考生交一份試卷,計數(shù)器就減一。直到考生都交了試卷(計數(shù)器為0),監(jiān)考老師(一個或多個)才能離開考場。至于考生是否做完試卷,監(jiān)考老師并不關注。只要都交了試卷,他就可以做接下來的工作了。

CountDownLatch實現(xiàn)原理

下面從構造方法開始,一步步解釋實現(xiàn)的原理:構造方法下面是實現(xiàn)的源碼,非常簡短,主要是創(chuàng)建了一個Sync對象。

public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}

Sync對象

private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
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;
}
}
}

假設我們是這樣創(chuàng)建的:new CountDownLatch(5)。其實也就相當于new Sync(5),相當于setState(5)。setState其實就是共享鎖資源總數(shù),我們可以暫時理解為設置一個計數(shù)器,當前計數(shù)器初始值為5。

tryAcquireShared方法其實就是判斷一下當前計數(shù)器的值,是否為0了,如果為0的話返回1(返回1的時候,就表示獲取鎖成功,awit()方法就不再阻塞)。

tryReleaseShared方法就是利用CAS的方式,對計數(shù)器進行減一的操作,而我們實際上每次調(diào)用countDownLatch.countDown()方法的時候,最終都會調(diào)到這個方法,對計數(shù)器進行減一操作,一直減到0為止。

countDownLatch.await()

public void await() throws InterruptedException { 
sync.acquireSharedInterruptibly(1); 
}

代碼很簡單,就一句話(注意acquireSharedInterruptibly()方法是抽象類:AbstractQueuedSynchronizer的一個方法,我們上面提到的Sync繼承了它),我們跟蹤源碼,繼續(xù)往下看:

acquireSharedInterruptibly(int arg) 
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}

源碼也是非常簡單的,首先判斷了一下,當前線程是否有被中斷,如果沒有的話,就調(diào)用tryAcquireShared(int acquires)方法,判斷一下當前線程是否還需要“阻塞”。其實這里調(diào)用的tryAcquireShared方法,就是我們上面提到的java.util.concurrent.CountDownLatch.Sync.tryAcquireShared(int)這個方法。

當然,在一開始我們沒有調(diào)用過countDownLatch.countDown()方法時,這里tryAcquireShared方法肯定是會返回-1的,因為會進入到doAcquireSharedInterruptibly方法。 

doAcquireSharedInterruptibly(int arg)

countDown()方法

// 計數(shù)器減1
public void countDown() {
sync.releaseShared(1); 
}
//調(diào)用AQS的releaseShared方法
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {//計數(shù)器減一
doReleaseShared();//喚醒后繼結點,這個時候隊列中可能只有調(diào)用過await()的線程節(jié)點,也可能隊列為空
return true;
}
return false;
}

這個時候,我們應該對于countDownLatch.await()方法是怎么“阻塞”當前線程的,已經(jīng)非常明白了。其實說白了,就是當你調(diào)用了countDownLatch.await()方法后,你當前線程就會進入了一個死循環(huán)當中,在這個死循環(huán)里面,會不斷的進行判斷,通過調(diào)用tryAcquireShared方法,不斷判斷我們上面說的那個計數(shù)器,看看它的值是否為0了(為0的時候,其實就是我們調(diào)用了足夠多 countDownLatch.countDown()方法的時候),如果是為0的話,tryAcquireShared就會返回1,代碼也會進入到圖中的紅框部分,然后跳出了循環(huán),也就不再“阻塞”當前線程了。

需要注意的是,說是在不停的循環(huán),其實也并非在不停的執(zhí)行for循環(huán)里面的內(nèi)容,因為在后面調(diào)用parkAndCheckInterrupt()方法時,在這個方法里面是會調(diào)用 LockSupport.park(this);來掛起當前線程。

CountDownLatch 使用的注意點:

1、只有當count為0時,await之后的程序才夠執(zhí)行。

2、countDown必須寫在finally中,防止發(fā)生異程常時,導致程序死鎖。

使用場景:

比如對于馬拉松比賽,進行排名計算,參賽者的排名,肯定是跑完比賽之后,進行計算得出的,翻譯成Java識別的預發(fā),就是N個線程執(zhí)行操作,主線程等到N個子線程執(zhí)行完畢之后,在繼續(xù)往下執(zhí)行。

public static void testCountDownLatch(){
int threadCount = 10;
final CountDownLatch latch = new CountDownLatch(threadCount);
for(int i=0; i< threadCount; i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("線程" + Thread.currentThread().getId() + "開始出發(fā)");
try {
Thread.sleep(1000);
System.out.println("線程" + Thread.currentThread().getId() + "已到達終點");
} catch (InterruptedException e) {
e.printStackTrace();
} fianlly {
latch.countDown();
}
}
}).start();
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("10個線程已經(jīng)執(zhí)行完畢!開始計算排名");
}

結果:

線程10開始出發(fā)
線程13開始出發(fā)
線程12開始出發(fā)
線程11開始出發(fā)
線程14開始出發(fā)
線程15開始出發(fā)
線程16開始出發(fā)
線程17開始出發(fā)
線程18開始出發(fā)
線程19開始出發(fā)
線程14已到達終點
線程15已到達終點
線程13已到達終點
線程12已到達終點
線程10已到達終點
線程11已到達終點
線程16已到達終點
線程17已到達終點
線程18已到達終點
線程19已到達終點
10個線程已經(jīng)執(zhí)行完畢!開始計算排名

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 并發(fā)編程模式之ThreadLocal源碼和圖文解讀

    并發(fā)編程模式之ThreadLocal源碼和圖文解讀

    這篇文章主要介紹了并發(fā)編程模式之ThreadLocal源碼和圖文解讀,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java的特點和優(yōu)點(動力節(jié)點整理)

    Java的特點和優(yōu)點(動力節(jié)點整理)

    由于Java語言的設計者們十分熟悉C++語言,所以在設計時很好地借鑒了C++語言。可以說,Java語言是一種比C++語言“還面向對象”的一種編程語言,下面通過本文說下java的特點和優(yōu)點
    2017-03-03
  • springboot中在非bean類中調(diào)用bean的實現(xiàn)方法

    springboot中在非bean類中調(diào)用bean的實現(xiàn)方法

    在Spring Boot中,非Bean類調(diào)用Bean方法通常需要通過靜態(tài)方法獲取Bean實例,然后調(diào)用相應的方法,這種方法避免了直接在非Bean類中注入Bean,保持了代碼的簡潔和可維護性,通過這種方式,可以在不改變原有代碼結構的情況下,實現(xiàn)Bean方法的調(diào)用
    2025-02-02
  • SpringBoot/Spring?AOP默認動態(tài)代理方式實例詳解

    SpringBoot/Spring?AOP默認動態(tài)代理方式實例詳解

    這篇文章主要給大家介紹了關于SpringBoot/Spring?AOP默認動態(tài)代理方式的相關資料,Spring AOP是一款基于Java的AOP框架,其中默認采用動態(tài)代理方式實現(xiàn)AOP功能,本文將詳細介紹動態(tài)代理的實現(xiàn)原理和使用方法,需要的朋友可以參考下
    2023-03-03
  • ConcurrentModificationException日志關鍵字報警思考分析

    ConcurrentModificationException日志關鍵字報警思考分析

    本文將記錄和分析日志中的ConcurrentModificationException關鍵字報警,還有一些我的思考,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2023-12-12
  • SpringBoot中如何打印Http請求日志

    SpringBoot中如何打印Http請求日志

    所有針對第三方的請求都強烈推薦打印請求日志,本文主要介紹了SpringBoot中如何打印Http請求日志,具有一定的參考價值,感興趣的可以了解一下
    2024-06-06
  • java播放聲音類和一個簡單示例

    java播放聲音類和一個簡單示例

    這篇文章主要介紹了一個java播放聲音類和一個java播放聲音的應用程序,應用程序可以單次播放聲音、循環(huán)播放聲音,需要的朋友可以參考下
    2014-03-03
  • SpringBoot 如何從配置文件讀取值到對象中

    SpringBoot 如何從配置文件讀取值到對象中

    這篇文章主要介紹了SpringBoot 如何從配置文件讀取值到對象中,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java 求解二維數(shù)組列最小值

    java 求解二維數(shù)組列最小值

    這篇文章主要介紹了java 求解二維數(shù)組列最小值的相關資料,需要的朋友可以參考下
    2017-05-05
  • Java中的延遲隊列DelayQueue詳細解析

    Java中的延遲隊列DelayQueue詳細解析

    這篇文章主要介紹了Java中的延遲隊列DelayQueue詳細解析,JDK自身支持延遲隊列的數(shù)據(jù)結構,其實類:java.util.concurrent.DelayQueue,<BR>我們通過閱讀源碼的方式理解該延遲隊列類的實現(xiàn)過程,需要的朋友可以參考下
    2023-12-12

最新評論

防城港市| 汉沽区| 资兴市| 嘉定区| 汤阴县| 日照市| 渝北区| 红原县| 额尔古纳市| 故城县| 泰顺县| 德令哈市| 阜新| 云阳县| 阿拉善盟| 长治县| 富阳市| 昭觉县| 和静县| 乐至县| 临朐县| 射阳县| 昌江| 洞口县| 丰顺县| 日土县| 灵丘县| 遂川县| 武威市| 兴宁市| 昌江| 衡阳市| 平定县| 杭锦后旗| 乌鲁木齐市| 蓬溪县| 金湖县| 兴宁市| 陆良县| 阿合奇县| 介休市|