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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java8 CountDownLatch 源码分析

發布時間:2024/9/30 java 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java8 CountDownLatch 源码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、CountDownLatch 概述

1.1 什么是 CountDLatch

閉鎖(CountDownLatch)是 java.util.concurrent 包下的一種同步工具類。閉鎖可以用來確保某些活動直到其他活動都完成后才執行。

閉鎖相當于一扇門:在閉鎖到達結束狀態之前,這扇門一直是關閉的,并且沒有任何線程能通過,當達到結束狀態時,這扇門會打開,并允許所有的線程通過。

1.2 CountDownLatch 的應用場景

  • 確保某個計算在其需要的所有資源都被初始化之后才執行
  • 確保某個服務在其依賴的所有其他服務都已經啟動之后才啟動
  • 等待直到每個操作的所有參與者都就緒再執行(比如打麻將時需要等待四個玩家就緒)

1.3 CountDownLatch 簡單應用

我們知道 4 個人玩紙牌游戲一定會先等所有玩家就緒后才會發牌,下面我們就來用閉鎖簡單的模擬一下。

public class CountDownLatchTest {/*** 初始化需要等待的 4 個事件*/private static CountDownLatch latch = new CountDownLatch(4);public static void main(String[] args) throws InterruptedException {// 創建 4 個線程分別代表 4 個玩家new Thread(() -> { System.out.println("玩家 1 已就緒"); latch.countDown(); }).start();new Thread(() -> { System.out.println("玩家 2 已就緒"); latch.countDown(); }).start();new Thread(() -> { System.out.println("玩家 3 已就緒"); latch.countDown(); }).start();new Thread(() -> { System.out.println("玩家 4 已就緒"); latch.countDown(); }).start();// 所有玩家就緒前一直阻塞latch.await();System.out.println("所有玩家已就緒,請發牌");} }

下面是控制臺輸出:

二、CountDownLatch 原理分析

CountDownLatch 底層是基于 AQS 實現的,如果不懂 AQS 原理的小伙伴需要先了解下 AQS 再來看這篇文章。

2.1 API 相關方法

構造函數:

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

CountDownLatch 內部有一個 Sync 同步對象,這個對象是一個內部類實現了 AQS,下面我們會具體來看方法實現。

await 方法:

public void await() throws InterruptedException {// 共享式檢查是否中斷,如果中斷拋出異常// 調用 tryAcquireShared 方法嘗試獲取同步狀態,當閉鎖內的線程執行完畢后嘗試獲取成功,直接返回sync.acquireSharedInterruptibly(1);}

countDown 方法:

public void countDown() {// 調用 releaseShared 每次使同步狀態值減 1sync.releaseShared(1);}

通過上面的 API 我們應該能知道其大概的原理了,在 CountDownLatch 初始化的時候會有一個初始的同步狀態值,這個同步狀態值可以理解為放行前的所要執行的線程數,每次調用 countDown 方法時就把同步狀態值減 1,await 方法會自旋檢查同步狀態值是否為 0,當不為 0 時會阻塞線程,當為 0 時會直接返回,該方法是支持相應 中斷的,當線程中斷時會拋出異常。因此該方法可以理解為一扇門,只有當指定數量的線程執行完后,才會執行后續的代碼。

上面我們已經理解了大概的流程,下面來看下具體的實現代碼。

2.2 Sync 同步類

private static final class Sync extends AbstractQueuedSynchronizer {// 初始化閉鎖 count 值Sync(int count) {setState(count);}int getCount() {return getState();}// 通過共享方式嘗試獲取鎖protected int tryAcquireShared(int acquires) {return (getState() == 0) ? 1 : -1;}// 通過共享方式嘗試釋放鎖// 因為該方法是線程共享的,因此需要通過 CAS 操作保證線程安全protected boolean tryReleaseShared(int releases) {for (;;) {int c = getState();// 同步狀態值在上一次置 0 時已經放行,因此返回 falseif (c == 0)return false;// 同步狀態值 - 1int nextc = c-1;// 為 0 時返回 trueif (compareAndSetState(c, nextc))return nextc == 0;}}}

內部代碼很簡單,如果你明白了 AQS 的內部原理,這些代碼是很容易理解的,如果你對這里的代碼感覺到陌生,那么你一定要好好的再去了解下 AQS 了。

AQS 的原理設計的很巧妙,相對來說也比較難理解,后面想梳理這塊內容的時候會嘗試著總結一下,如果你對這塊感興趣,也可以到我的 GitHub 去看對應的源碼。

jdk1.8 源碼閱讀:https://github.com/zchen96/jdk1.8-source-code-read

參考資料

《Java 并發編程實戰》

總結

以上是生活随笔為你收集整理的Java8 CountDownLatch 源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

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