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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

可口的JAVA-并发控制之CountDownLatch

發布時間:2025/1/21 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 可口的JAVA-并发控制之CountDownLatch 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

本文帶大家系統的學習一下CountDownLatch知識,從介紹、方法、場景、原理四個角度方面開展學習,話不多說,馬上開始。

一:介紹

CountDownLatch是一種同步輔助工具,允許一個或多個線程等待*其他線程中正在執行的一組操作完成。

CountDownLatch 使用給定的 count 進行初始化。* {await} 方法阻塞,直到當前計數達到零,因為調用了 {countDown} 方法,之后*所有等待線程被釋放,并且任何后續調用* {await } 立即返回。這是一種一次性現象,計數無法重置。如果您需要重置計數的版本,請考慮使用 CyclicBarrier。

二:方法

CountDownLatch類對外開放的方法有

  • void await(); 啟動線程等待
  • void countDown(); 等待數目減一
  • int getCount(); 獲取當前等待線程數目

    ** 分享一段代碼幫助大家理解**

    以幼兒園呼叫孩子們做游戲為例子,老師要一個一個通知到孩子,孩子們簽到,開始做游戲。 Flowerd.class

    /*** @class 孩子*/ class Flowerd implements Runnable{public Flowerd(CountDownLatch latch_s){latch = latch_s;}private CountDownLatch latch;@Overridepublic void run() {try {//1.孩子們反應時間不同,用一個隨機數Thread.sleep((int)(1000*Math.random()));System.out.println(Thread.currentThread().getName()+"::來了,還差【"+(latch.getCount()-1)+"】個人!");latch.countDown();} catch (InterruptedException e) {e.printStackTrace();}} } 復制代碼

    playGame.method

    /*** @function 喊孩子們做游戲*/ public static void playGame() {System.out.println("開始呼叫孩子們");CountDownLatch downLatch = new CountDownLatch(3);System.out.println("呼叫小明。。。");new Thread(new Flowerd(downLatch),"小明").start();System.out.println("呼叫小滑。。。");new Thread(new Flowerd(downLatch),"小滑").start();System.out.println("呼叫小六。。。");new Thread(new Flowerd(downLatch),"小六").start();System.out.println("孩子們呼叫完畢");try {downLatch.await();System.out.println("孩子們都來了,開始做游戲吧。。。。");} catch (InterruptedException e) {e.printStackTrace();} } 復制代碼

    執行結果:

    開始呼叫孩子們 呼叫小明。。。 呼叫小滑。。。 呼叫小六。。。 孩子們呼叫完畢 小滑::來了,還差【2】個人! 小六::來了,還差【1】個人! 小明::來了,還差【0】個人! 孩子們都來了,開始做游戲吧。。。。 復制代碼

    CountDownLatch初始化了三個孩子,主線程調用await阻塞,子線程調用countDown減一,當三個孩子全部報道后await方法自動釋放。 另外,await方法支持設置定時器,超時自動釋放。

    boolean await(long timeout, TimeUnit unit) 復制代碼

    替換代碼:

    downLatch.await(300l, TimeUnit.MILLISECONDS); 復制代碼

    替換后執行結果:

    開始呼叫孩子們 呼叫小明。。。 呼叫小滑。。。 呼叫小六。。。 孩子們呼叫完畢 小六::來了,還差【2】個人! 小滑::來了,還差【1】個人! 孩子們都來了,開始做游戲吧。。。。 小明::來了,還差【0】個人! 復制代碼

    三:場景

    大家了解了CountDownLatchiben方法和特性后,可以進行合理推測:countdownlatch就是一把等待 鎖,可以我等你也可以你等我,可以一個資源等多個資源,也可以多個資源等一個資源,延伸一下就是多個資源等多個資源。

    場景一:一個資源等多個資源

    某聚合接口的調用,需要整合底層多個服務調用結果,使用同步調用很顯然不行(除非客戶沒有性能方面要求),異步調用后整合子服務結果返回。

    public static void main(String[] args) {callAPI(); }/*** @function 模擬聚合接口調用*/ static void callAPI(){CountDownLatch latch = new CountDownLatch(3);//調用服務ASystem.out.println("進入api");System.out.println("調用A服務");FutureTask<Integer> ft1 = new FutureTask<>(new BaseService(latch));new Thread(ft1,"底層服務A").start();//調用服務BSystem.out.println("調用B服務");FutureTask<Integer> ft2 = new FutureTask<>(new BaseService(latch));new Thread(ft2,"底層服務B").start();//調用服務CSystem.out.println("調用C服務");FutureTask<Integer> ft3 = new FutureTask<>(new BaseService(latch));new Thread(ft3,"底層服務C").start();try {System.out.println("等待子服務調用結果。。。");latch.await();System.out.println("API結果為:【"+(ft1.get()+ft2.get()+ft3.get())+"】");} catch (InterruptedException e) {e.printStackTrace();}catch (ExecutionException e){e.printStackTrace();} } 復制代碼 /*** 可調用底層服務*/ class BaseService implements Callable<Integer>{private CountDownLatch latch;public BaseService(CountDownLatch latch1){latch = latch1;}@Overridepublic Integer call() throws Exception {Thread.sleep((int)Math.random()*1000);Integer re = (int)(Math.random()*10000);latch.countDown();System.out.println(Thread.currentThread().getName()+"服務執行完畢,返回【"+re+"】");return re;} } 復制代碼

    執行結果:

    進入api 調用A服務 調用B服務 調用C服務 等待子服務調用結果。。。 底層服務A服務執行完畢,返回【5643】 底層服務C服務執行完畢,返回【639】 底層服務B服務執行完畢,返回【3524】 API結果為:【9806】 復制代碼

    場景二:多個資源等一個資源

    運動場上,選手準備完畢后,等待裁判發令槍響,然后同時起跑。 示例代碼:

    /*** 運動員*/ class RunMan implements Runnable{public RunMan(CountDownLatch latch_s){latch = latch_s;}private CountDownLatch latch;@Overridepublic void run() {System.out.println("運動員【"+Thread.currentThread().getName()+"】準備完畢,等待裁判發令槍響。。。");try {latch.await();Thread.sleep((int)Math.random()*1000);System.out.println("運動員【"+Thread.currentThread().getName()+"】到達終點");} catch (InterruptedException e) {e.printStackTrace();}} } 復制代碼 public static void main(String[] args) {raceArea(); } /*** 賽場*/ static void raceArea(){System.out.println("開始準備");CountDownLatch downLatch = new CountDownLatch(1);new Thread(new RunMan(downLatch),"小明").start();new Thread(new RunMan(downLatch),"小滑").start();new Thread(new RunMan(downLatch),"小六").start();try {Thread.sleep(2000);System.out.println("裁判員開槍。。。。");downLatch.countDown();Thread.sleep(2000);System.out.println("比賽結束");} catch (InterruptedException e) {e.printStackTrace();}} 復制代碼

    執行結果:

    開始準備 運動員【小滑】準備完畢,等待裁判發令槍響。。。 運動員【小六】準備完畢,等待裁判發令槍響。。。 運動員【小明】準備完畢,等待裁判發令槍響。。。 裁判員開槍。。。。 運動員【小滑】到達終點 運動員【小明】到達終點 運動員【小六】到達終點 比賽結束 復制代碼

    場景三:多個資源等多個資源

    例如:汽車和電瓶車過馬路,首先要保證是綠燈,其次要保證沒有行人正在闖紅燈橫穿馬路,我們可以設置兩個線程(行人+綠燈)做等待條件,再設置兩個線程(汽車和電瓶車)做要執行的條件,與上述兩個功能都有類似之處,代碼大家調整修改一下就OK了,搞不定的評論一下我再寫。

    四:部分原理

    要點一:CountDownLatch內部使用了 AbstractQueuedSynchronizer(fifo)抽象同步隊列的來保證同步。 源碼01:

    要點二:采用cas樂觀鎖控制CountDownLatch的遞減,重寫了tryReleaseShared()方法。源碼02:

    要點三:CountDownLatch是不可重復指定的,只能初始化一次,這點和CyclicBarrier有區別。

總結

以上是生活随笔為你收集整理的可口的JAVA-并发控制之CountDownLatch的全部內容,希望文章能夠幫你解決所遇到的問題。

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