CyclicBarrier怎么用,和CountDownLatch有什么区别?(新手必看)
CyclicBarrier 与 CountDownLatch 一样,也是 JUC 中的同步工具类,它允许一组线程相互等待,直到所有线程都到达一个同步点(Barrier)后,这些线程才会继续执行。
在使用 CyclicBarrier 时,我们需要创建一个 CyclicBarrier 实例并指定一个整数,这个整数表示需要相互等待的线程数量。某个线程在到达同步点时会调用 await() 方法,该方法会阻塞线程直到所有参与的线程都到达了同步点。一旦最后一个线程到达同步点,即所有线程都到达了同步点,CyclicBarrier 会执行一个可选的处理操作,比如合并结果数据等。执行完处理操作后,所有被 await() 方法阻塞的线程会被释放,并可以继续执行。
CyclicBarrier 常用于处理并行编程中多个线程互相等待,需要保证所有线程都能够一起继续执行的场景。它的常见的应用场景包括并行计算中的大型计算任务分割、游戏开发中的多玩家游戏同步等。
下面我们看一个 CyclicBarrier 的使用示例,代码如下:
简单来讲,CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的。CountDownLatch 用于一个线程等待其他线程,而 CyclicBarrier 用于多个线程相互等待。
在使用 CyclicBarrier 时,我们需要创建一个 CyclicBarrier 实例并指定一个整数,这个整数表示需要相互等待的线程数量。某个线程在到达同步点时会调用 await() 方法,该方法会阻塞线程直到所有参与的线程都到达了同步点。一旦最后一个线程到达同步点,即所有线程都到达了同步点,CyclicBarrier 会执行一个可选的处理操作,比如合并结果数据等。执行完处理操作后,所有被 await() 方法阻塞的线程会被释放,并可以继续执行。
CyclicBarrier 常用于处理并行编程中多个线程互相等待,需要保证所有线程都能够一起继续执行的场景。它的常见的应用场景包括并行计算中的大型计算任务分割、游戏开发中的多玩家游戏同步等。
下面我们看一个 CyclicBarrier 的使用示例,代码如下:
import java.util.concurrent.CyclicBarrier; public class CyclicBarrierExample { // 创建一个 CyclicBarrier 实例 // 指定3个线程任务在执行完任务后需要在同步点互相等待 private static CyclicBarrier barrier = new CyclicBarrier(3); public static void main(String[] args) { // 创建并启动线程 for (int i = 0; i < 3; i++) { Thread worker = new Thread(new Worker(i)); worker.start(); } } static class Worker implements Runnable { private int id; public Worker(int id) { this.id = id; } @Override public void run() { try { System.out.println("Thread " + id + " 正在执行任务"); // 模拟任务执行时间 Thread.sleep((long) (Math.random() * 1000)); System.out.println("Thread " + id + " 到达同步点,正在等待其他线程"); // 调用 await() 方法等待其他线程 barrier.await(); System.out.println("Thread " + id + " 继续执行任务"); } catch (Exception e) { e.printStackTrace(); } } } }在上述示例中,我们创建了 3 个线程任务,它们在执行完任务后需要在同步点互相等待,直到所有线程都到达同步点,然后继续执行剩余的任务。
CyclicBarrier和CountDownLatch的区别
前面我们了解了 CyclicBarrier 的功能和使用,接下来了解 CyclicBarrier 和 CountDownLatch之 间的不同,它们在使用和功能上有明显的区别,主要如下。1) 功能和工作方式
- CountDownLatch:实现一个或多个线程等待其他线程完成操作,然后继续执行。它使用一个计数器,该计数器的值在初始化时设置,随后每调用一次 countDown() 方法,计数器的值就减 1;当计数器的值变为 0 时,所有调用 await() 方法而被阻塞的线程将被唤醒并继续执行。
- CyclicBarrier:实现一组线程互相等待,到达一个公共同步点后,这些线程再继续执行。CyclicBarrier 在初始化时需指定一个线程数量,当这些线程都到达了同步点时,可以执行一个可选的运行一次的处理动作,例如合并结果,然后这些线程继续执行。
2) 可重用性
- CountDownLatch:不能重置,一旦计数器的值变为 0,就不能再次使用了。如果需要再次使用,需要创建新的 CountDownLatch 实例。
- CyclicBarrier:可以重用,一旦所有等待的线程都到达了同步点,同步点就会被重置,然后可以再次使用。
3) 功能操作
- CountDownLatch:只涉及一个操作,即 countDown(),它用来减少计数器的值。所有等待的线程通过 await() 方法等待计数器的值变为0。
- CyclicBarrier:主要操作是等待所有线程到达,通过调用 await() 方法实现。使用 CyclicBarrier 时还可以通过构造函数设置一个处理操作,即编写一段处理代码,当所有线程都到达同步点时自动执行。
4) 应用场景
- CountDownLatch:通常被用于一组操作中,主线程需要等待其他线程完成任务后才能继续执行。例如,主线程需要等待服务的初始化。
- CyclicBarrier:适用于并行计算,多个线程必须互相等待直到所有线程都完成它们各自的任务,然后合并结果,进行下一步的操作。
简单来讲,CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的。CountDownLatch 用于一个线程等待其他线程,而 CyclicBarrier 用于多个线程相互等待。