Java 并发编程系列之闭锁(CountDownLatch)
在講閉鎖之前,我們先來思考一個問題:在多線程環境下,主線程打印一句話,如何保證這句話最后(其他線程全部執行完畢)打印?
博主目前可以想到的實現方式有兩種。一種是通過 join() 方法實現,另一種就是用閉鎖。如果大家有好的解決辦法,可以在下面留言,下面進入正題。
一、什么是閉鎖
閉鎖(CountDownLatch)是 java.util.concurrent 包下的一種同步工具類。閉鎖可以用來確保某些活動直到其他活動都完成后才執行。
閉鎖相當于一扇門:在閉鎖到達結束狀態之前,這扇門一直是關閉的,并且沒有任何線程能通過,當達到結束狀態時,這扇門會打開,并允許所有的線程通過。
下面是 CountDownLatch 中的方法:
CountDownLatch 中有一個計數器字段,在對象創建時初始化,表示需要等待的事件數量。countDown() 方法遞減計數器,表示有一個事件已經發生了,await() 方法等待計數器為 0 時,表示所有的需要等待的時間都已經發生。如果計數器的值非 0 會一直阻塞直到計數器為 0。
下面使用閉鎖來實現文章開頭的問題:
public class CountDownLatchTest {/*** 初始化需要等待的 3 個事件*/private static CountDownLatch latch = new CountDownLatch(3);public static void main(String[] args) throws InterruptedException {/*** 創建 3 個線程去執行事件*/new Thread(() -> {System.out.println("*****_*****");latch.countDown();}).start();new Thread(() -> {System.out.println("*****_*****");latch.countDown();}).start();new Thread(() -> {System.out.println("*****_*****");latch.countDown();}).start();// 在計數器為 0 之前會一直阻塞latch.await();System.out.println("~~~~~_~~~~~");} }執行結果:
二、閉鎖的用途
我們已經知道了閉鎖的使用方法,但是閉鎖都是有哪些應用場景呢?
- 確保某個計算在其需要的所有資源都被初始化之后才執行
- 確保某個服務在其依賴的所有其他服務都已經啟動之后才啟動
- 等待直到每個操作的所有參與者都就緒再執行(比如打麻將時需要等待四個玩家就緒)
CountDownLatch 底層是基于 AQS(AbstractQueuedSynchronizer)實現的,關于 AQS 的知識會在后續的博文中進行分析,大家有興趣的可以持續關注。
PS:在一開始提到了使用 join() 方法解決打印問題,下面把代碼貼出來供大家參考。
public class ThreadJoinTest {public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(() -> System.out.println("*****_*****"));Thread thread2 = new Thread(() -> System.out.println("*****_*****"));Thread thread3 = new Thread(() -> System.out.println("*****_*****"));thread1.start();thread2.start();thread3.start();/*** 作用:在 A 線程中調用了 B 線程的 join() 方法時,* 表示只有當 B 線程執行完畢時,A 線程才能繼續執行* 原理:調用了當前線程的 wait() 方法*/thread1.join();thread2.join();thread3.join();System.out.println("~~~~~_~~~~~");} }參考資料
《Java 并發編程實戰》
總結
以上是生活随笔為你收集整理的Java 并发编程系列之闭锁(CountDownLatch)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Boot 日志管理
- 下一篇: 人保助贷险是坑吗