Java併發程式設計札記-(四)JUC鎖-08CountDownLatch
CountDownLatch是一個通用同步器,用於同步一個或多個任務。在完成一組正在其他執行緒中執行的任務之前,它允許一個或多個執行緒一直等待。
可以用一個初始計數值來初始化CountDownLatch物件,任何在這個物件上呼叫wait()的方法都將阻塞,直至計數值到達0。每完成一個任務,都可以在這個物件上呼叫countDown()減少計數值。當計數值減為0,所有等待的執行緒都會被釋放。CountDownLatch的計數值不能重置。如果需要重置計數器,請考慮使用CyclicBarrier。
使用場景
作為一個通用同步工具,CountDownLatch有許多用途。比如,將計數值初始化為1的CountDownLatch用作一個簡單的開/關:在通過呼叫countDown()的執行緒開啟入口前,所有呼叫await()的執行緒都一直在入口處等待;用N初始化的 CountDownLatch可以使一個執行緒在N個執行緒完成某項操作之前一直等待,或者使其在某項操作完成N次之前一直等待。
例1:CountDownLatch作為開關
public class Driver {
public static void main(String args[]) throws InterruptedException {
int n = 5;
// 啟動訊號,在driver為繼續執行worker做好準備之前,它會阻止所有的worker繼續執行。
CountDownLatch startSignal = new CountDownLatch(1);
// 完成訊號,它允許driver在完成所有 worker之前一直等待。
CountDownLatch doneSignal = new CountDownLatch(n);
for (int i = 0; i < n; ++i) // 建立並啟動所有執行緒
new Thread(new Worker(startSignal, doneSignal)).start();
Thread.sleep(1000);
startSignal.countDown(); // 開啟startSignal開關,執行所有等待的任務
doneSignal.await();// 等待doneSignal計數器為0,即所有任務執行完
System.out.println("down");
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
System.out.println(Thread.currentThread().getName() + "啟動了");
startSignal.await();// 使當前執行緒在鎖存器startSignal倒計數至零之前一直等待
System.out.println(Thread.currentThread().getName() + "工作了");
doneSignal.countDown();// 遞減鎖存器doneSignal的計數
} catch (InterruptedException ex) {
}
}
}
執行結果為:
Thread-2啟動了
Thread-0啟動了
Thread-1啟動了
Thread-3啟動了
Thread-4啟動了
Thread-2工作了
Thread-3工作了
Thread-1工作了
Thread-4工作了
Thread-0工作了
down
從結果中看到,5個任務執行緒依次啟動,但每一個都沒有執行完,這是因為run方法中的startSignal.await();
使當前執行緒在鎖存器startSignal倒計數至零之前一直等待。直到startSignal.countDown();
開啟startSignal開關,才執行所有等待的任務。
例2:CountDownLatch分割任務
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Driver2 {
public static void main(String args[]) throws InterruptedException {
int n = 5;
ExecutorService exec = Executors.newCachedThreadPool();
// 完成訊號,它允許driver在完成所有 worker之前一直等待。
CountDownLatch doneSignal = new CountDownLatch(n);
// 建立並啟動所有執行緒
for (int i = 0; i < n; ++i)
exec.execute(new WorkerRunnable(doneSignal, i));
// 等待doneSignal計數器為0,即所有任務執行完
doneSignal.await();
System.out.println("down");
exec.shutdown();
}
}
class WorkerRunnable implements Runnable {
private final CountDownLatch doneSignal;
private final int i;
WorkerRunnable(CountDownLatch doneSignal, int i) {
this.doneSignal = doneSignal;
this.i = i;
}
public void run() {
System.out.println("任務" + i + "完成了");
doneSignal.countDown();// 遞減鎖存器doneSignal的計數
}
}
原始碼
待補充
本文就講到這裡,想了解Java併發程式設計更多內容請參考: