核心概念
CyclicBarrier和CountDownLatch都是Java并发编程中的工具,用于协调多线程之间的同步。虽然它们都用于等待一组线程完成某项任务,但它们的使用场景和行为有一些关键的区别。
CyclicBarrier
适合在所有的子任务完成后才执行一个公共任务的情况,CyclicBarrier允许一组线程互相等待,直到所有线程都达到某个屏障点(barrier point),这个屏障点是一个位置,每个线程都必须在此停止执行,直到所有线程都达到这个屏障点,当所有线程到达屏障点时,它们才会继续执行,CyclicBarrier可以重复使用,即一旦所有线程都通过屏障后,屏障可以再次被设置。
CountDownLatch
适合在主线程需要等待其他线程完成各自任务后才能继续执行的情况,CountDownLatch允许一个或多个线程等待其他线程完成,它有一个计数器,初始化为一个正数,表示需要完成的线程数,每当一个线程完成任务时,计数器就递减1。当计数器到达0时,所有等待的线程都将被释放并继续执行,CountDownLatch不能重复使用,一旦计数器到达0,就不能再被重置。
因此,CyclicBarrier是同步屏障,可以让一组线程在特定点暂停并等待其他线程;而CountDownLatch是计数器,让一个或多个线程等待其他线程完成特定任务。
代码实现
下面演示了如何使用CyclicBarrier
来同步一组线程,如下代码:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
final int totalThread = 5;
CyclicBarrier cyclicBarrier = new CyclicBarrier(totalThread);
for (int i = 0; i < totalThread; i++) {
new Thread(() -> {
System.out.println("线程" + Thread.currentThread().getId() + "已经准备就绪");
try {
// 线程在此等待,直到所有线程都达到这个屏障点
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getId() + "开始处理任务");
}).start();
}
}
}
在上面年代码中,创建了一个CyclicBarrier
实例,并指定了需要等待的线程总数(totalThread
),然后,创建了这些线程,并且每个线程在启动后都会打印一条消息表示它已经准备就绪,接着,每个线程调用cyclicBarrier.await()
方法进入等待状态,直到所有线程都调用了这个方法。一旦所有线程都调用了await()
方法并且达到了屏障点,它们将同时继续执行,并打印出下一条消息表示它们开始处理任务。
下面演示了如何使用CountDownLatch
来等待一组线程完成它们的任务,如下代码:
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
int totalThread = 5;
CountDownLatch countDownLatch = new CountDownLatch(totalThread);
for (int i = 0; i < totalThread; i++) {
new Thread(() -> {
System.out.println("线程" + Thread.currentThread().getId() + "开始执行任务");
try {
// 模拟任务执行
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getId() + "任务执行完毕");
// 通知CountDownLatch任务已完成
countDownLatch.countDown();
}).start();
}
// 主线程在此等待,直到所有子线程的任务都完成
countDownLatch.await();
System.out.println("所有线程的任务都已完成,主线程继续执行");
}
}
在上满代码其中,创建了一个CountDownLatch
实例,初始化计数为totalThread
,这表示需要等待的线程总数,然后,创建了这些线程,并且每个线程在启动后都会打印一条消息表示它开始执行任务。接着,每个线程执行一些模拟任务(这里使用Thread.sleep()
来模拟任务耗时),然后在任务完成后调用countDownLatch.countDown()
来减少计数器的值。
主线程调用countDownLatch.await()
方法进入等待状态,直到计数器减少到0(即所有线程都完成了它们的任务),一旦所有线程都完成了任务并且计数器达到了0,主线程将继续执行,并打印出一条消息表示所有线程的任务都已完成。
CountDownLatch
是一次性的,一旦计数器到达0,它就不能再被重置。