java使用CountDownLatch實現(xiàn)多線程協(xié)作
前言
在多線程編程中,經(jīng)常需要實現(xiàn)一種機制來協(xié)調(diào)多個線程的執(zhí)行,以確保某些操作在所有線程完成后再進(jìn)行。CountDownLatch 就是 Java 并發(fā)包中提供的一種同步工具,它能夠讓一個或多個線程等待其他線程完成操作。
了解 CountDownLatch
概括
CountDownLatch 是Java 1.5版本推出的一個同步輔助類,在構(gòu)造時需要指定一個計數(shù)值,該計數(shù)值表示需要等待的事件數(shù)量。每當(dāng)一個事件完成時,計數(shù)值就會減一,當(dāng)計數(shù)值減至零時,等待的線程就會被喚醒繼續(xù)執(zhí)行。
CountDownLatch 的應(yīng)用場景
CountDownLatch 可以被廣泛應(yīng)用于各種多線程協(xié)作的場景,例如:
- 主線程等待多個子線程完成后再執(zhí)行下一步操作。
- 多個子任務(wù)并行執(zhí)行,最后合并結(jié)果。
- 并行計算中,等待所有計算任務(wù)完成后進(jìn)行統(tǒng)一匯總。
使用案例
讓我們通過一個示例代碼來理解 CountDownLatch 的使用。假設(shè)有一個任務(wù)需要被分配給多個子線程來完成,并且主線程需要等待所有子線程執(zhí)行完畢后才能繼續(xù)執(zhí)行。
//任務(wù)分割的線程數(shù) private static final int THREAD_TOTAL = 10; //子線程執(zhí)行的超時時間 private static final int countDownLatchTimeout = 5; public static void main(String[] args) { //創(chuàng)建CountDownLatch并設(shè)置計數(shù)值,該count值可以根據(jù)線程數(shù)的需要設(shè)置 CountDownLatch countDownLatch = new CountDownLatch(THREAD_TOTAL); //創(chuàng)建線程池,開啟、創(chuàng)建異步線程執(zhí)行任務(wù) ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < THREAD_TOTAL; i++) { cachedThreadPool.execute(() -> { try { Thread.sleep(5000); System.out.println(Thread.currentThread().getName() + " do something!"); } catch (Exception e) { System.out.println("Exception: do something exception"); } finally { //該線程執(zhí)行完畢-1 countDownLatch.countDown(); } }); } //回到主線程中 System.out.println("Back main thread do something"); try { //主線程等待線程池中完成(子線程執(zhí)行超時時間) boolean await = countDownLatch.await(countDownLatchTimeout, TimeUnit.MINUTES); System.out.println(await); } catch (InterruptedException e) { System.out.println("Exception: await interrupted exception"); } finally { System.out.println("countDownLatch: " + countDownLatch); } System.out.println("main thread do something-2"); }
CountDownLatch 的優(yōu)缺點分析
優(yōu)點
- 簡單易用:CountDownLatch 的使用非常簡單,通過 await 和 countDown 方法即可實現(xiàn)多線程的協(xié)作。
- 靈活性:可以根據(jù)具體場景指定等待的計數(shù)值,可以靈活控制多個線程的協(xié)作關(guān)系。
- 高效性:底層使用了 AQS(AbstractQueuedSynchronizer)來實現(xiàn)同步,能夠保證高效地協(xié)調(diào)多個線程的執(zhí)行順序。
缺點
- 一次性:CountDownLatch 的計數(shù)值只能減少,無法重置。一旦計數(shù)值減至零,就不能再次使用。
- 無法中途取消:一旦等待開始,就無法中途取消等待,除非等待超時或者發(fā)生中斷。
如果您學(xué)有余力或手頭沒有著急的需求,請繼續(xù)往下看,讓我們簡單從源碼層面分析下CountDownLatch的實現(xiàn)。
從源碼層面分析CountDownLatch的實現(xiàn)
實現(xiàn)
我截取了CountDownLatch
內(nèi)部關(guān)鍵實現(xiàn)邏輯來分析其實現(xiàn)原理:
CountDownLatch
的功能主要通過內(nèi)部類Sync
實現(xiàn),在內(nèi)部類中,Sync
繼承自AbstractQueuedSynchronizer
來實現(xiàn)同步操作,AbstractQueuedSynchronizer
提供了同步器實現(xiàn)的基礎(chǔ)框架,通過該類,開發(fā)者可以相對容易地實現(xiàn)自定義的同步器,例如獨占鎖、共享鎖、信號量等。
/** * Synchronization control For CountDownLatch. * Uses AQS state to represent count. */ 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; } } } private final Sync sync; public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); } public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1); }
- Sync :定義了一個名為 Sync 的靜態(tài)內(nèi)部類,它繼承自 AbstractQueuedSynchronizer 類,這個類通常被用于實現(xiàn)鎖和相關(guān)的同步器。
- count:定義了一個序列化版本號,用于在對象序列化和反序列化時進(jìn)行版本控制。同時count在CountDownLatch的構(gòu)造方法中用于設(shè)置當(dāng)前狀態(tài),即:編碼人員傳入的計數(shù)值。
- getCount:獲取當(dāng)前狀態(tài)值,即剩余的計數(shù)值。
- tryAcquireShared:嘗試獲取共享資源,如果當(dāng)前狀態(tài)為0,則返回1表示成功獲取資源,否則返回-1表示獲取資源失敗。
tryReleaseShared
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; } }
tryReleaseShared 方法嘗試釋放共享資源,首先通過一個無限循環(huán)不斷嘗試,在循環(huán)中獲取當(dāng)前狀態(tài)值,如果狀態(tài)值已經(jīng)為0,則直接返回false;否則將狀態(tài)值減1,并嘗試原子性地設(shè)置狀態(tài)值,如果設(shè)置成功,則返回是否狀態(tài)值變?yōu)?,否則繼續(xù)循環(huán)。
總的來說,這段代碼實現(xiàn)了一個簡單的 CountDownLatch 功能,通過 tryAcquireShared 方法嘗試獲取共享資源,通過 tryReleaseShared 方法嘗試釋放共享資源。當(dāng)共享資源的狀態(tài)值為0時,表示所有等待的線程都已被釋放。
擴展
CompletableFuture簡述
在JDK 1.8后,java.util.concurrent
包提供了CompletableFuture
類用于支持異步編程和異步任務(wù)的處理,相較于CountDownLatch
,它提供了更豐富的API,就個人而言,我更喜歡CompletableFuture
,因為它擴展性強,更適合JDK 8提供的函數(shù)式編程特性,代碼更加優(yōu)雅。
CompletableFuture 的優(yōu)缺點
優(yōu)點
- 功能強大:CompletableFuture 提供了豐富的方法和組合操作,可以實現(xiàn)復(fù)雜的異步編程邏輯。
- 支持異常處理:可以通過 exceptionally 或 handle 方法方便地處理異步操作中的異常情況。
- 支持組合操作:可以通過 thenCompose、thenCombine 等方法方便地進(jìn)行多個 CompletableFuture 的組合操作。
缺點
- 學(xué)習(xí)曲線較陡:相對于 CountDownLatch,CompletableFuture 的使用可能需要更多的學(xué)習(xí)和理解異步編程的概念。
- 復(fù)雜度較高:在復(fù)雜的業(yè)務(wù)場景下,可能會出現(xiàn)嵌套回調(diào)、異常處理困難等問題,增加了代碼的復(fù)雜度。
總結(jié)
CountDownLatch 和 CompletableFuture 都是 Java 中用于多線程協(xié)作的工具,它們各自適用于不同的場景。CountDownLatch 更適合簡單的多線程協(xié)作,而 CompletableFuture 則更適合復(fù)雜的異步編程場景。在實際應(yīng)用中,我們可以根據(jù)具體的需求選擇合適的工具來實現(xiàn)多線程協(xié)作和異步編程,以達(dá)到更好的開發(fā)效率和代碼質(zhì)量。
以上就是java使用CountDownLatch實現(xiàn)多線程協(xié)作的詳細(xì)內(nèi)容,更多關(guān)于java CountDownLatch的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot統(tǒng)一數(shù)據(jù)返回的幾種方式
在Web應(yīng)用程序開發(fā)中,統(tǒng)一數(shù)據(jù)返回格式對于前后端分離項目尤為重要,本文就來介紹一下SpringBoot統(tǒng)一數(shù)據(jù)返回的幾種方式,具有一定的參考價值,感興趣的可以了解一下2024-07-07SSM如何實現(xiàn)在Controller中添加事務(wù)管理
這篇文章主要介紹了SSM如何實現(xiàn)在Controller中添加事務(wù)管理,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02Java調(diào)用Deepseek實現(xiàn)項目代碼審查
這篇文章主要為大家詳細(xì)介紹了Java如何調(diào)用Deepseek實現(xiàn)項目代碼審查功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-02-02java?Object轉(zhuǎn)Integer實現(xiàn)方式
這篇文章主要介紹了java?Object轉(zhuǎn)Integer實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07IDEA編譯報錯:Error:java:無效的源發(fā)行版:17的解決辦法
IDEA里面裝了幾個版本的JDK,導(dǎo)入工程后時不時提示一下錯誤,下面這篇文章主要給大家介紹了關(guān)于IDEA編譯報錯:Error:java:無效的源發(fā)行版:17的解決辦法,需要的朋友可以參考下2023-01-01SpringBoot操作Mongodb的實現(xiàn)示例
本文主要介紹了SpringBoot操作Mongodb的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06