日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java并发计数器_浅谈java并发之计数器CountDownLatch

發布時間:2023/12/19 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java并发计数器_浅谈java并发之计数器CountDownLatch 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

CountDownLatch簡介

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

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

CountDownLatch實現原理

下面從構造方法開始,一步步解釋實現的原理:構造方法下面是實現的源碼,非常簡短,主要是創建了一個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;

}

}

}

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

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

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

countDownLatch.await()

public void await() throws InterruptedException {

sync.acquireSharedInterruptibly(1);

}

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

acquireSharedInterruptibly(int arg)

public final void acquireSharedInterruptibly(int arg)

throws InterruptedException {

if (Thread.interrupted())

throw new InterruptedException();

if (tryAcquireShared(arg) < 0)

doAcquireSharedInterruptibly(arg);

}

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

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

doAcquireSharedInterruptibly(int arg)

countDown()方法

// 計數器減1

public void countDown() {

sync.releaseShared(1);

}

//調用AQS的releaseShared方法

public final boolean releaseShared(int arg) {

if (tryReleaseShared(arg)) {//計數器減一

doReleaseShared();//喚醒后繼結點,這個時候隊列中可能只有調用過await()的線程節點,也可能隊列為空

return true;

}

return false;

}

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

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

CountDownLatch 使用的注意點:

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

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

使用場景:

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

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() + "開始出發");

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個線程已經執行完畢!開始計算排名");

}

結果:

線程10開始出發

線程13開始出發

線程12開始出發

線程11開始出發

線程14開始出發

線程15開始出發

線程16開始出發

線程17開始出發

線程18開始出發

線程19開始出發

線程14已到達終點

線程15已到達終點

線程13已到達終點

線程12已到達終點

線程10已到達終點

線程11已到達終點

線程16已到達終點

線程17已到達終點

線程18已到達終點

線程19已到達終點

10個線程已經執行完畢!開始計算排名

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

總結

以上是生活随笔為你收集整理的java并发计数器_浅谈java并发之计数器CountDownLatch的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。