欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2019年06月06日 11:28:53   作者:exposure  
CountDownLatch是通過(guò)一個(gè)計(jì)數(shù)器來(lái)實(shí)現(xiàn)的,當(dāng)我們?cè)趎ew 一個(gè)CountDownLatch對(duì)象的時(shí)候需要帶入該計(jì)數(shù)器值,該值就表示了線程的數(shù)量。下面我們來(lái)深入了解一下吧

CountDownLatch簡(jiǎn)介

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

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

CountDownLatch實(shí)現(xiàn)原理

下面從構(gòu)造方法開(kāi)始,一步步解釋實(shí)現(xiàn)的原理:構(gòu)造方法下面是實(shí)現(xiàn)的源碼,非常簡(jiǎn)短,主要是創(chuàng)建了一個(gè)Sync對(duì)象。

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

Sync對(duì)象

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;
}
}
}

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

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

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

countDownLatch.await()

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

代碼很簡(jiǎn)單,就一句話(注意acquireSharedInterruptibly()方法是抽象類(lèi):AbstractQueuedSynchronizer的一個(gè)方法,我們上面提到的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);
}

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

當(dāng)然,在一開(kāi)始我們沒(méi)有調(diào)用過(guò)countDownLatch.countDown()方法時(shí),這里tryAcquireShared方法肯定是會(huì)返回-1的,因?yàn)闀?huì)進(jìn)入到doAcquireSharedInterruptibly方法。 

doAcquireSharedInterruptibly(int arg)

countDown()方法

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

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

需要注意的是,說(shuō)是在不停的循環(huán),其實(shí)也并非在不停的執(zhí)行for循環(huán)里面的內(nèi)容,因?yàn)樵诤竺嬲{(diào)用parkAndCheckInterrupt()方法時(shí),在這個(gè)方法里面是會(huì)調(diào)用 LockSupport.park(this);來(lái)掛起當(dāng)前線程。

CountDownLatch 使用的注意點(diǎn):

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

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

使用場(chǎng)景:

比如對(duì)于馬拉松比賽,進(jìn)行排名計(jì)算,參賽者的排名,肯定是跑完比賽之后,進(jìn)行計(jì)算得出的,翻譯成Java識(shí)別的預(yù)發(fā),就是N個(gè)線程執(zhí)行操作,主線程等到N個(gè)子線程執(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() + "開(kāi)始出發(fā)");
try {
Thread.sleep(1000);
System.out.println("線程" + Thread.currentThread().getId() + "已到達(dá)終點(diǎn)");
} catch (InterruptedException e) {
e.printStackTrace();
} fianlly {
latch.countDown();
}
}
}).start();
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("10個(gè)線程已經(jīng)執(zhí)行完畢!開(kāi)始計(jì)算排名");
}

結(jié)果:

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

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java 將一個(gè)字符重復(fù)n遍過(guò)程詳解

    Java 將一個(gè)字符重復(fù)n遍過(guò)程詳解

    這篇文章主要介紹了Java 將一個(gè)字符重復(fù)n遍過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • springboot2.5.2與 flowable6.6.0整合流程引擎應(yīng)用分析

    springboot2.5.2與 flowable6.6.0整合流程引擎應(yīng)用分析

    這篇文章主要介紹了springboot2.5.2與 flowable6.6.0整合流程引擎應(yīng)用分析,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-07-07
  • Javassist用法詳解

    Javassist用法詳解

    這篇文章主要介紹了Javassist用法的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-02-02
  • 最新版Spring Security中的路徑匹配方案

    最新版Spring Security中的路徑匹配方案

    在 Spring Security 中,路徑匹配是權(quán)限控制的核心部分,它決定了哪些請(qǐng)求可以訪問(wèn)特定的資源,本文將詳細(xì)介紹 Spring Security 中的路徑匹配策略,并提供相應(yīng)的代碼示例,需要的朋友可以參考下
    2024-04-04
  • Java實(shí)現(xiàn)去掉字符串重復(fù)字母的方法示例

    Java實(shí)現(xiàn)去掉字符串重復(fù)字母的方法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)去掉字符串重復(fù)字母的方法,涉及java針對(duì)字符串的遍歷、判斷、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下
    2017-12-12
  • java并發(fā)編程專(zhuān)題(十)----(JUC原子類(lèi))基本類(lèi)型詳解

    java并發(fā)編程專(zhuān)題(十)----(JUC原子類(lèi))基本類(lèi)型詳解

    這篇文章主要介紹了java JUC原子類(lèi)基本類(lèi)型詳解的相關(guān)資料,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • Java的類(lèi)型擦除式泛型詳解

    Java的類(lèi)型擦除式泛型詳解

    Java語(yǔ)言中的泛型只存在于程序源碼之中,在編譯后的字節(jié)碼文件里,則全部泛型都會(huì)被替換為原來(lái)的原始類(lèi)型(Raw Type),并且會(huì)在相應(yīng)的地方插入強(qiáng)制轉(zhuǎn)型的代碼。這篇文章主要介紹了Java的類(lèi)型擦除式泛型,需要的朋友可以參考下
    2021-08-08
  • MyBatis通用Mapper和PageHelper的過(guò)程詳解

    MyBatis通用Mapper和PageHelper的過(guò)程詳解

    這篇文章主要介紹了MyBatis通用Mapper和PageHelper的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • http協(xié)議進(jìn)階之Transfer-Encoding和HttpCore實(shí)現(xiàn)詳解

    http協(xié)議進(jìn)階之Transfer-Encoding和HttpCore實(shí)現(xiàn)詳解

    這篇文章主要給大家介紹了http協(xié)議之Transfer-Encoding和HttpCore實(shí)現(xiàn)的相關(guān)資料,文中介紹的非常詳細(xì),相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-04-04
  • Java 互相關(guān)聯(lián)的實(shí)體無(wú)限遞歸問(wèn)題的解決

    Java 互相關(guān)聯(lián)的實(shí)體無(wú)限遞歸問(wèn)題的解決

    這篇文章主要介紹了Java 互相關(guān)聯(lián)的實(shí)體無(wú)限遞歸問(wèn)題的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10

最新評(píng)論