当多个线程需求协调和同步履行使命时,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(); // 主线程等候三个工人线程完结使命
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,在实际的项目中进步多线程编程的效率和质量。