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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

JUC锁-CountDownLatch(六)

發布時間:2024/2/28 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JUC锁-CountDownLatch(六) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

CountDownLatch介紹

CountDownLatch是一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。

uml類圖

CountDownLatch的數據結構很簡單,它是通過”共享鎖”實現的。它包含了sync對象,sync是Sync類型。Sync是實例類,它繼承于AQS。

CountDownLatch源碼分析

1. CountDownLatch(int count)

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

該函數是創建一個Sync對象,而Sync是繼承于AQS類。Sync構造函數如下:

Sync(int count) {setState(count); }

setState()在AQS中實現,源碼如下:

protected final void setState(long newState) {state = newState; }

說明:在AQS中,state是一個private volatile long類型的對象。對于CountDownLatch而言,state表示的”鎖計數器“。CountDownLatch中的getCount()最終是調用AQS中的getState(),返回的state對象,即”鎖計數器“。

2.await()

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

說明:該函數實際上是調用的AQS的acquireSharedInterruptibly(1);

AQS中的acquireSharedInterruptibly()的源碼如下:

public final void acquireSharedInterruptibly(long arg)throws InterruptedException {//如果當前線程是中斷狀態,則拋出異常InterruptedExceptionif (Thread.interrupted())throw new InterruptedException();//調用tryAcquireShared(arg)嘗試獲取共享鎖,嘗試成功則返回//否則就調用doAcquireSharedInterruptibly()if (tryAcquireShared(arg) < 0)doAcquireSharedInterruptibly(arg); }

tryAcquireShared()在CountDownLatch.java中被重寫,它的源碼如下:

protected int tryAcquireShared(int acquires) {return (getState() == 0) ? 1 : -1; }

如果”鎖計數器=0”,即鎖是可獲取狀態,則返回1;否則,鎖是不可獲取狀態,則返回-1。

doAcquireSharedInterruptibly()方法

private void doAcquireSharedInterruptibly(long arg)throws InterruptedException {// 創建"當前線程"的Node節點,且Node中記錄的鎖是"共享鎖"類型;并將該節點添加到CLH隊列末尾。final Node node = addWaiter(Node.SHARED);boolean failed = true;try {for (;;) {// 獲取上一個節點。// 如果上一節點是CLH隊列的表頭,則"嘗試獲取共享鎖"。final Node p = node.predecessor();if (p == head) {long r = tryAcquireShared(arg);if (r >= 0) {setHeadAndPropagate(node, r);p.next = null; // help GCfailed = false;return;}}// (上一節點不是CLH隊列的表頭) 當前線程一直等待,直到獲取到共享鎖。// 如果線程在等待過程中被中斷過,則再次中斷該線程(還原之前的中斷狀態)。if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);} }

doAcquireSharedInterruptibly()會使當前線程一直等待,直到當前線程獲取到共享鎖(或被中斷)才返回。跟共享鎖ReadLock的doAcquireShare()方法非常類似,這里就不進行贅述了。

3. countDown()

public void countDown() {sync.releaseShared(1); }

說明:該函數實際上調用releaseShared(1)釋放共享鎖。
releaseShared()在AQS中實現,源碼如下:

public final boolean releaseShared(int arg) {if (tryReleaseShared(arg)) {doReleaseShared();return true;}return false; }

說明:releaseShared()的目的是讓當前線程釋放它所持有的共享鎖。
它首先會通過tryReleaseShared()去嘗試釋放共享鎖。嘗試成功,則直接返回;嘗試失敗,則通過doReleaseShared()去釋放共享鎖。

tryReleaseShared()在CountDownLatch.java中被重寫,源碼如下:

protected boolean tryReleaseShared(int releases) {// Decrement count; signal when transition to zerofor (;;) {// 獲取“鎖計數器”的狀態int c = getState();if (c == 0)return false;// “鎖計數器”-1int nextc = c-1;// 通過CAS函數進行賦值。if (compareAndSetState(c, nextc))return nextc == 0;} }

說明:tryReleaseShared()的作用是釋放共享鎖,將“鎖計數器”的值-1。

總結:CountDownLatch是通過“共享鎖”實現的。在創建CountDownLatch中時,會傳遞一個int類型參數count,該參數是“鎖計數器”的初始狀態,表示該“共享鎖”最多能被count給線程同時獲取。當某線程調用該CountDownLatch對象的await()方法時,該線程會等待“共享鎖”可用時,才能獲取“共享鎖”進而繼續運行。而“共享鎖”可用的條件,就是“鎖計數器”的值為0!而“鎖計數器”的初始值為count,每當一個線程調用該CountDownLatch對象的countDown()方法時,才將“鎖計數器”-1;通過這種方式,必須有count個線程調用countDown()之后,“鎖計數器”才為0,而前面提到的等待線程才能繼續運行!

CountDownLatch的使用示例

import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier;public class CountDownLatchTest1 {private static int LATCH_SIZE = 5;private static CountDownLatch doneSignal;public static void main(String[] args) {try {doneSignal = new CountDownLatch(LATCH_SIZE);// 新建5個任務for(int i=0; i<LATCH_SIZE; i++)new InnerThread().start();System.out.println("main await begin.");// "主線程"等待線程池中5個任務的完成doneSignal.await();System.out.println("main await finished.");} catch (InterruptedException e) {e.printStackTrace();}}static class InnerThread extends Thread{public void run() {try {Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " sleep 1000ms.");// 將CountDownLatch的數值減1doneSignal.countDown();} catch (InterruptedException e) {e.printStackTrace();}}} }

運行結果:

main await begin. Thread-0 sleep 1000ms. Thread-2 sleep 1000ms. Thread-1 sleep 1000ms. Thread-4 sleep 1000ms. Thread-3 sleep 1000ms. main await finished.

總結

以上是生活随笔為你收集整理的JUC锁-CountDownLatch(六)的全部內容,希望文章能夠幫你解決所遇到的問題。

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