您好,登录后才能下订单哦!
在并发编程中,CountDownLatch
是一个非常有用的同步工具类。它允许一个或多个线程等待其他线程完成操作后再继续执行。CountDownLatch
通过一个计数器来实现同步,计数器的初始值通常设置为需要等待的线程数量。每当一个线程完成了自己的任务后,计数器就会减一。当计数器减到零时,等待的线程就会被唤醒,继续执行。
CountDownLatch
的构造函数接受一个整数参数,表示计数器的初始值。例如:
CountDownLatch latch = new CountDownLatch(3);
这里创建了一个初始值为 3 的 CountDownLatch
,表示需要等待 3 个线程完成任务。
主线程可以通过调用 await()
方法来等待其他线程完成任务。await()
方法会阻塞当前线程,直到计数器的值减到零。
latch.await();
每个线程在完成任务后,可以通过调用 countDown()
方法来减少计数器的值。每次调用 countDown()
方法,计数器的值都会减一。
latch.countDown();
下面是一个简单的示例,展示了如何使用 CountDownLatch
来同步多个线程:
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
int numThreads = 3;
CountDownLatch latch = new CountDownLatch(numThreads);
for (int i = 0; i < numThreads; i++) {
new Thread(new Worker(latch)).start();
}
// 主线程等待所有子线程完成任务
latch.await();
System.out.println("所有线程已完成任务,主线程继续执行");
}
static class Worker implements Runnable {
private final CountDownLatch latch;
Worker(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 正在执行任务");
Thread.sleep(1000); // 模拟任务执行时间
System.out.println(Thread.currentThread().getName() + " 任务完成");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown(); // 任务完成后减少计数器
}
}
}
}
在这个示例中,主线程创建了 3 个子线程,并使用 CountDownLatch
来等待这些子线程完成任务。每个子线程在完成任务后都会调用 countDown()
方法,减少计数器的值。当计数器的值减到零时,主线程就会被唤醒,继续执行。
CountDownLatch
最常见的应用场景是多线程任务的同步。例如,在一个多线程任务中,主线程需要等待所有子线程完成任务后再继续执行。这种情况下,可以使用 CountDownLatch
来实现同步。
在某些情况下,我们可能需要同时启动多个线程来执行并行任务。使用 CountDownLatch
可以确保所有线程都准备好后再同时启动。
import java.util.concurrent.CountDownLatch;
public class ParallelTaskStartExample {
public static void main(String[] args) throws InterruptedException {
int numThreads = 3;
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(numThreads);
for (int i = 0; i < numThreads; i++) {
new Thread(new Worker(startSignal, doneSignal)).start();
}
System.out.println("所有线程已准备就绪,准备同时启动");
startSignal.countDown(); // 启动所有线程
doneSignal.await(); // 等待所有线程完成任务
System.out.println("所有线程已完成任务");
}
static class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
@Override
public void run() {
try {
startSignal.await(); // 等待启动信号
System.out.println(Thread.currentThread().getName() + " 正在执行任务");
Thread.sleep(1000); // 模拟任务执行时间
System.out.println(Thread.currentThread().getName() + " 任务完成");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
doneSignal.countDown(); // 任务完成后减少计数器
}
}
}
}
在这个示例中,主线程使用 startSignal
来同时启动所有子线程,并使用 doneSignal
来等待所有子线程完成任务。
在某些复杂的多线程任务中,任务可能分为多个阶段。每个阶段的任务完成后,才能进入下一个阶段。这种情况下,可以使用多个 CountDownLatch
来实现多阶段任务的同步。
import java.util.concurrent.CountDownLatch;
public class MultiPhaseTaskExample {
public static void main(String[] args) throws InterruptedException {
int numThreads = 3;
CountDownLatch phase1Latch = new CountDownLatch(numThreads);
CountDownLatch phase2Latch = new CountDownLatch(numThreads);
for (int i = 0; i < numThreads; i++) {
new Thread(new Worker(phase1Latch, phase2Latch)).start();
}
phase1Latch.await(); // 等待所有线程完成第一阶段任务
System.out.println("所有线程已完成第一阶段任务,准备进入第二阶段");
phase2Latch.await(); // 等待所有线程完成第二阶段任务
System.out.println("所有线程已完成第二阶段任务");
}
static class Worker implements Runnable {
private final CountDownLatch phase1Latch;
private final CountDownLatch phase2Latch;
Worker(CountDownLatch phase1Latch, CountDownLatch phase2Latch) {
this.phase1Latch = phase1Latch;
this.phase2Latch = phase2Latch;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 正在执行第一阶段任务");
Thread.sleep(1000); // 模拟第一阶段任务执行时间
System.out.println(Thread.currentThread().getName() + " 第一阶段任务完成");
phase1Latch.countDown(); // 第一阶段任务完成后减少计数器
System.out.println(Thread.currentThread().getName() + " 正在执行第二阶段任务");
Thread.sleep(1000); // 模拟第二阶段任务执行时间
System.out.println(Thread.currentThread().getName() + " 第二阶段任务完成");
phase2Latch.countDown(); // 第二阶段任务完成后减少计数器
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
在这个示例中,主线程使用 phase1Latch
和 phase2Latch
来分别等待所有子线程完成第一阶段和第二阶段的任务。
CountDownLatch
的计数器一旦减到零,就不能再重置。如果需要重复使用计数器,可以考虑使用 CyclicBarrier
。
如果主线程在等待 CountDownLatch
时被中断,await()
方法会抛出 InterruptedException
。因此,在使用 CountDownLatch
时,需要妥善处理线程中断的情况。
在使用 CountDownLatch
时,确保每个线程在完成任务后都会调用 countDown()
方法。如果某个线程没有调用 countDown()
方法,主线程将一直处于等待状态,导致程序无法继续执行。
CountDownLatch
是 Java 并发编程中一个非常有用的工具类,它可以帮助我们实现多线程任务的同步。通过合理地使用 CountDownLatch
,我们可以确保主线程在所有子线程完成任务后再继续执行,从而实现复杂的并发控制逻辑。在实际开发中,CountDownLatch
常用于多线程任务的同步、并行任务的启动以及多阶段任务的同步等场景。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。