這篇文章將介紹CountDownLatch這個同步工具類的基本資訊以及通過案例來介紹如何使用這個工具。
CountDownLatch是java.util.concurrent
包下面的一個工具類,可以用來協調多個執行緒之間的同步,或者說起到執行緒之間的通訊(而不是用作互斥的作用)。 它可以允許一個或者多個執行緒等待其他執行緒完成操作。
案例
模擬遊戲一開始需要載入一些基礎資料後才能開始遊戲,基礎資料載入完可以繼續載入其他資料。基礎資料包含人物、地圖、背景、物品等等。
解決方案
利用CountDownLatch
來實現,基礎資料載入完畢後,CountDownLatch
計數器進行減一操作。當CountDownLatch
計數器為0時,表示可以開始遊戲。 示意圖如下
定義抽象類
定義抽象類AbstractDataRunnable
並實現Runnable
介面
抽象類包含兩個屬性
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
計數器進行減一操作.計數器減一之後可以繼續載入額外的資料,並不影響當前執行緒
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();
}
複製程式碼
定義一些資料載入類
背景資料載入類如下,實現了抽象類AbstractDataRunnable
的handle()
方法,在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.可以開始遊戲...
複製程式碼
案例原始碼地址:github.com/rainbowda/l…
有興趣的點個Star