當多個線程需要協調和同步執行任務時,Java中的CountDownLatch(倒計時門閂)是一個常用的工具類,本文將介紹 CountDownLatch 的基本原理、用法以及示例代碼,需要的朋友可以參考下
CountDownLatch 的基本原理
CountDownLatch 是基於計數器的原理實現的,它內部維護了一個整型的計數器。創建一個 CountDownLatch 對象時,需要指定一個初始計數值,該計數值表示需要等待的線程數量。每當一個線程完成了其任務,它調用 CountDownLatch 的 countDown() 方法,計數器的值就會減一。當計數器的值變成 0 時,等待的線程就會被喚醒,繼續執行它們的任務。
CountDownLatch 的用法
CountDownLatch 在多線程編程中有廣泛的應用場景,例如主線程等待所有子線程完成任務後再繼續執行,多個線程協同完成一個任務等。以下是 CountDownLatch 的基本用法:
- 創建 CountDownLatch 對象,並指定初始計數值。
CountDownLatch latch = new CountDownLatch(3); // 初始計數值爲 3
- 創建需要等待的線程,線程完成任務後調用 countDown() 方法。
Runnable task = new Runnable() {
@Override
public void run() {
// 線程任務邏輯
// ...
latch.countDown(); // 完成任務後調用 countDown()
}
};
- 創建等待線程,等待計數器的值變成 0 後再繼續執行。
try {
latch.await(); // 等待計數器的值變成 0
// 繼續執行需要等待的線程後續邏輯
} catch (InterruptedException e) {
// 處理中斷異常
e.printStackTrace();
}
CountDownLatch 示例
下面通過一個簡單的示例代碼來演示 CountDownLatch 的用法。假設有一個需求,需要三個工人協同完成一項任務,主線程需要等待三個工人完成任務後才能繼續執行。示例代碼如下:
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) {
final int workerCount = 3;
final CountDownLatch latch = new CountDownLatch(workerCount);
// 創建並啓動三個工人線程
for (int i = 0; i < workerCount; i++) {
Worker worker = new Worker(latch, "Worker " + (i + 1));
new Thread(worker).start();
}
try {
System.out.println("Main thread is waiting for workers to finish...");
latch.await(); // 主線程加鎖等待三個工人線程完成任務(latch.countDown()執行到0之後,才能執行latch.await()下面的代碼)
System.out.println("All workers have finished, main thread continues...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class Worker implements Runnable {
private final CountDownLatch latch;
private final String name;
public Worker(CountDownLatch latch, String name) {
this.latch = latch;
this.name = name;
}
@Override
public void run() {
System.out.println(name + " starts working...");
// 模擬工作耗時
try {
Thread.sleep((long) (Math.random() * 10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + " finishes working.");
latch.countDown(); // 工人完成任務後調用 countDown()
}
}
}
在上述代碼中,首先創建了一個 CountDownLatch 對象,並指定初始計數值爲 3。然後創建了三個工人線程並啓動,每個工人線程模擬完成一項工作後調用 countDown() 方法,計數器的值減一。最後,主線程調用 await() 方法等待計數器的值變成 0,表示所有工人都完成任務後再繼續執行。
運行該程序後,輸出結果如下:
Worker 1 starts working...
Worker 2 starts working...
Worker 3 starts working...
Main thread is waiting for workers to finish...
Worker 2 finishes working.
Worker 1 finishes working.
Worker 3 finishes working.
All workers have finished, main thread continues...
可以看到,主線程在三個工人線程完成任務後才繼續執行,並且所有工人線程的完成順序是不確定的,但主線程會一直等待直到所有工人完成任務。
擴展:上面的worker線程運行是沒有順序的,我們可以使用join()來使線程有序等待上一個線程運行結束。
public static void main(String[] args) throws InterruptedException {
final int workerCount = 3;
final CountDownLatch latch = new CountDownLatch(workerCount);
System.out.println("Main thread is waiting for workers to finish...");
// 創建並啓動三個工人線程
for (int i = 0; i < workerCount; i++) {
Worker worker = new Worker(latch, "Worker " + (i + 1));
Thread t = new Thread(worker);
t.start();
t.join(); // 等待上一個線程執行完成
}
try {
latch.await(); // 主線程等待三個工人線程完成任務
System.out.println("All workers have finished, main thread continues...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
輸出結果:
Main thread is waiting for workers to finish...
Worker 1 starts working...
Worker 1 finishes working.
Worker 2 starts working...
Worker 2 finishes working.
Worker 3 starts working...
Worker 3 finishes working.
All workers have finished, main thread continues...
CountDownLatch 和 join 的作用和使用方式不同。CountDownLatch 用於等待多個線程完成任務後再繼續執行,而 join 用於等待一個線程執行完畢後再繼續執行。另外,CountDownLatch 是基於計數器的實現,可以靈活地控制線程的數量和完成順序;而 join 方法只能等待單個線程執行完畢。
總結
CountDownLatch 是一個非常實用的線程同步工具,在多線程編程中有着廣泛的應用。它基於計數器的原理實現,通過等待計數器的值變成 0 來實現線程的同步和協作。在使用 CountDownLatch 時,需要注意初始計數值的設定和 countDown() 和 await() 方法的使用。 本文介紹了 CountDownLatch 的基本原理和用法,並通過示代碼演示了它的使用。希望本文能夠幫助讀者更好地理解和應用 CountDownLatch,在實際的項目中提高多線程編程的效率和質量。