java多線程系列:CountDownLatch

這篇文章將介紹CountDownLatch這個同步工具類的基本信息以及經過案例來介紹如何使用這個工具。java

CountDownLatch是java.util.concurrent包下面的一個工具類,能夠用來協調多個線程之間的同步,或者提及到線程之間的通訊(而不是用做互斥的做用)。 它能夠容許一個或者多個線程等待其餘線程完成操做。
圖片來源於網絡git

案例

模擬遊戲一開始須要加載一些基礎數據後才能開始遊戲,基礎數據加載完能夠繼續加載其餘數據。基礎數據包含人物、地圖、背景、物品等等。github

解決方案

利用CountDownLatch來實現,基礎數據加載完畢後,CountDownLatch計數器進行減一操做。當CountDownLatch計數器爲0時,表示能夠開始遊戲。 示意圖以下網絡

定義抽象類

定義抽象類AbstractDataRunnable並實現Runnable接口ide

抽象類包含兩個屬性函數

private String name;
private CountDownLatch count;

經過構造函數初始化兩個屬性工具

public AbstractDataRunnable(String name, CountDownLatch count) {
    this.name = name;
    this.count = count;
}

定義方法,提供一個抽象方法handle()供子類去實現,getName()afterCountDown()提供默認的實現。測試

public String getName() {
    return name;
}

public abstract void handle() throws InterruptedException;

public void afterCountDown(){
    System.out.println(this.getName() + ":CountDownLatch計數減一以後,繼續加載其餘數據...");
};

run方法以下,在調用handle()方法以後執行count.countDown();,讓CountDownLatch計數器進行減一操做.計數器減一以後能夠繼續加載額外的數據,並不影響當前線程this

public void run() {
    try {
        System.out.println(this.getName()+" 開始加載...");
        Long l1 = System.currentTimeMillis();
        handle();
        Long l2 = System.currentTimeMillis();
        System.out.println(this.getName()+" 加載完成,花費時間:"+(l2-l1));
    } catch (Exception e){
        e.printStackTrace();
    } finally {
        count.countDown();
    }
    afterCountDown();
}

定義一些數據加載類

背景數據加載類以下,實現了抽象類AbstractDataRunnablehandle()方法,在handle()方法休眠了2秒線程

public class BackGroundData extends AbstractDataRunnable {

    public BackGroundData(String name, CountDownLatch count) {
        super(name, count);
    }

    @Override
    public void handle() throws InterruptedException {
        //模擬加載時間,2秒
        Thread.sleep(2000);
    }
}

其餘數據加載類代碼就不貼出來了,睡眠的時間不一樣而已

開始遊戲

開始遊戲類以下,經過構造函數傳入CountDownLatch計數器,而後在run方法中執行count.await();方法進行等待基礎數據加載完畢。

class StartGame implements Runnable{
    private CountDownLatch count;

    public StartGame(CountDownLatch count) {
        this.count = count;
    }

    @Override
    public void run() {
        try {
            System.out.println("開始加載基礎數據...");
            Long l1 = System.currentTimeMillis();
            count.await();
            Long l2 = System.currentTimeMillis();
            System.out.println("基礎數據加載完畢,總共花費時長:"+(l2-l1)+".能夠開始遊戲...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

測試

public static void main(String[] args) throws IOException {
    CountDownLatch count = new CountDownLatch(4);

    //主線程
    Thread startGameThread = new Thread(new StartGame(count));
    startGameThread.start();

    //加載數據線程
    Thread mapThread = new Thread(new MapData("地圖",count));
    Thread goodsThread = new Thread(new GoodsData("物品",count));
    Thread personageThread = new Thread(new PersonageData("人物",count));
    Thread backGroundThread = new Thread(new BackGroundData("背景",count));


    mapThread.start();
    goodsThread.start();
    personageThread.start();
    backGroundThread.start();

    System.in.read();
}

測試結果內容

開始加載基礎數據...
地圖 開始加載...
物品 開始加載...
人物 開始加載...
背景 開始加載...
人物 加載完成,花費時間:1000
人物:CountDownLatch計數減一以後,繼續加載其餘數據...
背景 加載完成,花費時間:2000
背景:CountDownLatch計數減一以後,繼續加載其餘數據...
物品 加載完成,花費時間:2501
物品:CountDownLatch計數減一以後,繼續加載其餘數據...
地圖 加載完成,花費時間:3001
地圖:CountDownLatch計數減一以後,繼續加載其餘數據...
基礎數據加載完畢,總共花費時長:3003.能夠開始遊戲...

案例源代碼地址:https://github.com/rainbowda/learnWay/tree/master/learnConcurrency/src/main/java/com/learnConcurrency/utils/countDownLatch

有興趣的點個Star

相關文章
相關標籤/搜索