Java並發包之CountDownLatch用法


CountDownLatch計數器閉鎖是一個能阻塞主線程,讓其他線程滿足特定條件下主線程再繼續執行的線程同步工具。

 

Latch閉鎖的意思,是一種同步的工具類。類似於一扇門:在閉鎖到達結束狀態之前,這扇門一直是關閉着的,不允許任何線程通過,當到達結束狀態時,這扇門會打開並允許所有的線程通過。且當門打開了,就永遠保持打開狀態。

 

CountDowmLatch是一種靈活的閉鎖實現,包含一個計數器,該計算器初始化為一個正數,表示需要等待事件的數量。countDown方法遞減計數器,表示有一個事件發生,而await方法等待計數器到達0,表示所有需要等待的事情都已經完成。

 

這句話的意思是:在單獨主線程的情況下,創建多個子線程, 在保證主線程同步的情況下,同時又讓多個子線程處理,可以使用 CountDownLatch來阻塞主線程,等待子線程執行完成,主線程才執行后續操作.

常見案例:

1:多線程讀取批量文件, 並且讀取完成之后匯總處理

2:多線程讀取Excel多個sheet,讀取完成之后獲取匯總獲取的結果

3:多個人一起一起來吃飯,主人等待客人到來,客人一個個從不同地方來到飯店,主人需要等到所有人都到來之后,才能開飯

4:汽車站,所有乘客都從不同的地方趕到汽車站,必須等到所有乘客都到了,汽車才會出發,如果設置了超時等待,那么當某個時間點到了,汽車也出發

 

作用:可以用來確保某些活動直到其他活動都完成后才繼續執行。

注意事項:

使用CountDownLatch必須確保計數器數量與子線程數量一致,且countDown必須要執行,否則出現計數器不為0,導致主線程一致等待的情況

 

在執行任務的線程中,使用了try...finally結構,該結構可以保證創建的線程發生異常時CountDownLatch.countDown()方法也會執行,也就保證了主線程不會一直處於等待狀態。

CountDownLatch非常適合於對任務進行拆分,使其並行執行,比如某個任務執行2s,其對數據的請求可以分為五個部分,那么就可以將這個任務拆分為5個子任務,分別交由五個線程執行,執行完成之后再由主線程進行匯總,此時,總的執行時間將決定於執行最慢的任務,平均來看,還是大大減少了總的執行時間。

 

具體代碼示例:

模擬乘客登機的場景

package com.puppy.demo;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

//劉小品
public class CountDownLatchTest {

    public static void main(String[] args) throws InterruptedException {

        System.out.println("南京祿口機場_機長正在等待所有乘客登機");
        //CountDownLatch的計數器數量必須與線程的數量一致,否則可能出現一直等待的情況,即計數器不為0的情況
        //使用CountDownLatch 需要注意,子線程中的countDown()最好放到finnally里面,防止計數器不為0
        CountDownLatch latch = new CountDownLatch(3);

        ExecutorService ex = Executors.newCachedThreadPool();
        ex.execute(new ThreadTest1(latch));
        ex.execute(new ThreadTest2(latch));
        ex.execute(new ThreadTest3(latch));
        //等待所有乘客來機場
        System.out.println("所有乘客都在趕飛機的路上");

        //latch.await(1,TimeUnit.SECONDS);//模擬超時等待的情況
        latch.await(); //模擬等待的情況,不考慮子線程的處理實際
        System.out.println("南京祿口機場_機長啟動飛機起飛");
        ex.shutdown();
    }

}

class ThreadTest1 extends Thread {

    CountDownLatch lanch;

    public ThreadTest1() {

    }

    public ThreadTest1(CountDownLatch lanch) {
        this.lanch = lanch;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("正在馬鞍山,准備趕到南京坐飛機,需要1小時的車程到機場");
        lanch.countDown();
    }
}

class ThreadTest2 extends Thread {

    CountDownLatch lanch;

    public ThreadTest2() {

    }

    public ThreadTest2(CountDownLatch lanch) {
        this.lanch = lanch;
    }

    @Override
    public void run() {
        System.out.println("正在徐州,准備趕到南京坐飛機,需要5小時的車程到機場");
        lanch.countDown();
    }
}

class ThreadTest3 extends Thread {
    CountDownLatch lanch;

    public ThreadTest3() {

    }

    public ThreadTest3(CountDownLatch lanch) {
        this.lanch = lanch;
    }

    @Override
    public void run() {
        System.out.println("正在蕪湖,准備趕到南京坐飛機,需要2小時的車程到機場");
        lanch.countDown();
    }
}

執行結果

latch.await()

南京祿口機場_機長正在等待所有乘客登機
所有乘客都在趕飛機的路上
正在徐州,准備趕到南京坐飛機,需要5小時的車程到機場
正在蕪湖,准備趕到南京坐飛機,需要2小時的車程到機場
正在馬鞍山,准備趕到南京坐飛機,需要1小時的車程到機場
南京祿口機場_機長啟動飛機起飛

 

超時等待的情況:latch.await(1,TimeUnit.SECONDS)

主線程已經執行完成,但是子線程才結束,latch.await(1,TimeUnit.SECONDS)方法

南京祿口機場_機長正在等待所有乘客登機
所有乘客都在趕飛機的路上
正在徐州,准備趕到南京坐飛機,需要5小時的車程到機場
正在蕪湖,准備趕到南京坐飛機,需要2小時的車程到機場
南京祿口機場_機長啟動飛機起飛
正在馬鞍山,准備趕到南京坐飛機,需要1小時的車程到機場

  

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM