問題
當主線程的任務執行,需要依賴多個子線程運行結束後才能往下執行時如何解決,比如文件分段下載,同時開啓多個子線程進行文件的分段下載,當下載完成之後,再進行組裝。
有一種解決方式,便是在子線程下載完成之後,都進行子線程的回調並判斷是否所有子線程都已經執行完畢。
而CountDownLatch
便是java
在1.5提供的解決如上問題的工具類
阿里的ARouter
的攔截器相關,就是用該工具類
概述
CountDownLatch
是通過一個計數器來實現的,計數器的初始值是線程的數量。然後通過調用await()
完成阻塞,每當一個線程執行完畢後,計數器的值就-1,當計數器的值爲0時,表示所有線程都執行完畢,然後阻塞會被打開。
使用
初始化CountDownLatch
並設置子線程數量
CountDownLatch latch = new CountDownLatch(2);
創建子線程並啓動,並在子線程結束時,調用countDown()進行計數器更新
es1.execute(new Runnable() {
@Override
public void run() {
Thread.sleep(3000);
System.out.println("子線程:" + Thread.currentThread().getName() + "執行");
// 核心方法
latch.countDown();
}
});
主線程進行等待
latch.await();
該方法同時提供了一個重載方法,可以設置阻塞的時間,如果超時,直接執行,跳過阻塞。
public boolean await(long timeout, TimeUnit unit)
CyclicBarrier比對
CountDownLatch
執行一次,完成之後就結束了。CyclicBarrier
可以使用多次。比如有4個線程,每個線程內部都分爲3個子任務,而每個線程都需要保持子任務的同步,即4個線程都執行完自己的第一個任務之後,纔開始往下執行第二個任務。
例如
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(getName() + " 任務1");
barrier.await();
System.out.println(getName() + " 任務2");
Thread.sleep(1500);
barrier.await();
Thread.sleep(2000);
System.out.println(getName() + " 任務3");
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}
多個run
會先打印完任務1
纔開始打印任務2