Phaser、CountDownLatch 和 CyclicBarrier 区别对比

1. CountDownLatch - 等待所有子任务完成

特点:

一次性,不能重用。

适用于主线程等待所有子线程完成任务

子线程完成任务后调用 countDown() 递减计数,主线程 await() 等待计数变为 0 后继续执行。

示例:

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        int taskCount = 3;
        CountDownLatch latch = new CountDownLatch(taskCount);

        for (int i = 0; i < taskCount; i++) {
            final int taskId = i;
            new Thread(() -> {
                System.out.println("任务 " + taskId + " 开始执行...");
                try {
                    Thread.sleep((long) (Math.random() * 2000)); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务 " + taskId + " 完成!");
                latch.countDown(); // 任务完成,计数器 -1
            }).start();
        }

        System.out.println("等待所有任务完成...");
        latch.await(); // 阻塞,直到 countDown 变为 0
        System.out.println("所有任务已完成,主线程继续执行!");
    }
}

输出示例:

任务 0 开始执行...
任务 1 开始执行...
任务 2 开始执行...
等待所有任务完成...
任务 1 完成!
任务 0 完成!
任务 2 完成!
所有任务已完成,主线程继续执行!

2. CyclicBarrier - 线程到达屏障后同步执行

特点:

可以重用,多个线程到达屏障后一起继续执行

所有线程都要 await(),才能一起继续

可指定 barrierAction 作为回调,在所有线程到达时执行额外任务。

示例:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public static void main(String[] args) {
        int numThreads = 3;
        CyclicBarrier barrier = new CyclicBarrier(numThreads, () -> {
            System.out.println(">>> 所有线程已到达屏障,执行 BarrierAction <<<");
        });

        for (int i = 0; i < numThreads; i++) {
            final int threadId = i;
            new Thread(() -> {
                System.out.println("线程 " + threadId + " 准备执行任务...");
                try {
                    Thread.sleep((long) (Math.random() * 2000)); // 模拟任务执行
                    System.out.println("线程 " + threadId + " 到达屏障点,等待其他线程...");
                    barrier.await(); // 等待所有线程到达屏障
                    System.out.println("线程 " + threadId + " 继续执行!");
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

输出示例:

线程 0 准备执行任务...
线程 1 准备执行任务...
线程 2 准备执行任务...
线程 2 到达屏障点,等待其他线程...
线程 0 到达屏障点,等待其他线程...
线程 1 到达屏障点,等待其他线程...
>>> 所有线程已到达屏障,执行 BarrierAction <<<
线程 1 继续执行!
线程 2 继续执行!
线程 0 继续执行!

3. Phaser - 多阶段同步

特点:

可重用,支持多阶段

支持动态增加或减少线程,比 CountDownLatchCyclicBarrier 更灵活。

每个阶段线程不同,arriveAndAwaitAdvance() 进入下一个阶段

示例:

import java.util.concurrent.Phaser;

public class PhaserExample {
    public static void main(String[] args) {
        Phaser phaser = new Phaser(1); // 注册主线程

        for (int i = 0; i < 3; i++) {
            phaser.register(); // 动态增加线程
            final int threadId = i;
            new Thread(() -> {
                System.out.println("线程 " + threadId + " 开始执行阶段 1...");
                phaser.arriveAndAwaitAdvance(); // 等待所有线程完成阶段 1

                System.out.println("线程 " + threadId + " 进入阶段 2...");
                phaser.arriveAndAwaitAdvance(); // 等待所有线程完成阶段 2

                System.out.println("线程 " + threadId + " 进入阶段 3...");
                phaser.arriveAndDeregister(); // 线程完成所有阶段,注销
            }).start();
        }

        while (!phaser.isTerminated()) {
            int phase = phaser.getPhase();
            System.out.println("主线程等待第 " + phase + " 阶段完成...");
            phaser.arriveAndAwaitAdvance(); // 控制主线程进入下一个阶段
        }

        System.out.println("所有阶段完成,主线程退出!");
    }
}

输出示例:

线程 0 开始执行阶段 1...
线程 1 开始执行阶段 1...
线程 2 开始执行阶段 1...
主线程等待第 0 阶段完成...
线程 0 进入阶段 2...
线程 1 进入阶段 2...
线程 2 进入阶段 2...
主线程等待第 1 阶段完成...
线程 0 进入阶段 3...
线程 1 进入阶段 3...
线程 2 进入阶段 3...
主线程等待第 2 阶段完成...
所有阶段完成,主线程退出!

4. 选择指南

需求推荐方案
让主线程等待所有子任务完成后再执行CountDownLatch
让一批线程同步后一起执行下一步CyclicBarrier
任务有多个阶段,每个阶段线程可能不同Phaser
任务不可重复,只执行一次CountDownLatch
任务需要循环多次执行CyclicBarrier
线程数动态变化Phaser
<think>好的,用户之前问了Java的并发工具有哪些,现在又接着问PhaserCyclicBarrier是什么。这说明他们对这两个同步器的具体功能使用场景不太清楚,需要更详细的解释。 首先,我需要回忆一下CyclicBarrierPhaser的基本概念。CyclicBarrier是让一组线程相互等待,达到一个共同屏障点后再继续执行,适合分阶段的任务。而PhaserJava 7引入的,功能更强大,支持动态调整参的线程数,分多个阶段处理,每个阶段都可以有不同的屏障点。 用户可能是在实际开发中遇到了需要多线程协作的问题,比如分阶段处理任务,或者需要动态增减线程的情况。他们可能已经知道CountDownLatch,但现在需要更灵活的工具,所以才会问到这两个类。 接下来要比较两者的区别,让用户明白在什么情况下选择哪一个。比如CyclicBarrier的线程数是固定的,而Phaser可以动态注册注销,还支持分层结构,适合更复杂的场景。同时,Phaser的每个阶段结束后可以执行特定逻辑,而CyclicBarrier只能在所有线程到达后触发一个动作。 要注意用户可能对术语不太熟悉,所以需要用简单的例子说明。比如CyclicBarrier的例子可以用多线程处理数据,然后合并结果;Phaser的例子可以用多阶段的任务,比如游戏中的多个关卡,每个关卡需要不同的线程协作。 还要指出Phaser的优点,比如灵活性高,适合任务分解合并,而CyclicBarrier适合固定线程数的分阶段处理。同时提醒用户根据具体需求选择,避免不必要的复杂性。 最后,总结两者的关键区别,帮助用户做出决策。确保解释清晰,结构分明,让用户能快速理解两者的适用场景差异。</think>好的!`Phaser` `CyclicBarrier` 都是 Java 并发工具中用于多线程同步的类,但它们的设计目标功能有明显差异。以下是两者的对比详细说明: --- ### **1. CyclicBarrier(循环屏障)** #### **核心功能** - **目的**:让一组线程相互等待,直到所有线程都到达某个屏障点(Barrier)后,再一起继续执行。 - **复用性**:屏障可以重复使用(即“循环”特性),适合分阶段任务的场景。 - **触发动作**:可定义一个 `Runnable` 任务,在所有线程到达屏障时自动执行(例如合并数据)。 #### **使用场景** - **分阶段任务**:例如多线程分别处理数据的不同部分,全部处理完后合并结果。 - **模拟压力测试**:多个线程同时就绪后并发请求。 #### **代码示例** ```java int threadCount = 3; CyclicBarrier barrier = new CyclicBarrier(threadCount, () -> { System.out.println("所有线程已到达屏障,开始执行下一阶段"); }); for (int i = 0; i < threadCount; i++) { new Thread(() -> { try { System.out.println("线程到达屏障,等待其他线程"); barrier.await(); // 等待其他线程 System.out.println("所有线程就绪,继续执行"); } catch (Exception e) { /* ... */ } }).start(); } ``` #### **关键特性** - **固定线程数**:初始化时指定线程数量,不可动态调整。 - **一次同步**:所有线程到达屏障后,自动重置屏障供下一阶段使用。 --- ### **2. Phaser(阶段器)** #### **核心功能** - **目的**:比 `CyclicBarrier` 更灵活的同步器,支持**分阶段的多线程协作****动态调整参线程数**。 - **阶段推进**:所有线程完成当前阶段后,自动进入下一阶段(类似多个 `CyclicBarrier` 串联)。 - **动态注册**:允许线程随时注册(`register()`)或注销(`arriveAndDeregister()`)。 #### **使用场景** - **动态任务分解**:例如游戏关卡中,每个关卡需要不同数量的线程协作。 - **分层任务**:多阶段流水线处理(如数据处理 → 验证 → 存储)。 #### **代码示例** ```java Phaser phaser = new Phaser(1); // 初始注册数为1(控制线程自身) // 创建3个工作线程 for (int i = 0; i < 3; i++) { phaser.register(); // 动态注册新线程 new Thread(() -> { doWork(); phaser.arriveAndDeregister(); // 完成工作并注销 }).start(); } // 主线程等待所有阶段完成 phaser.arriveAndAwaitAdvance(); System.out.println("所有阶段完成"); ``` #### **关键特性** - **动态线程数**:通过 `register()` `deregister()` 调整参线程数。 - **分阶段控制**:每个阶段(Phase)结束后自动推进到下一阶段。 - **分层结构**:支持树形结构的 `Phaser`,降低大规模线程同步的开销。 --- ### **3. 两者的核心区别** | 特性 | CyclicBarrier | Phaser | |---------------------|-----------------------------|----------------------------------| | **线程数动态性** | 固定(初始化时指定) | 动态(可随时注册/注销) | | **阶段推进** | 手动重置屏障 | 自动分阶段(无需手动重置) | | **触发动作** | 仅在所有线程到达时执行一次 | 每个阶段结束后可自定义逻辑 | | **复杂度** | 简单 | 复杂(支持分层、动态调整) | --- ### **4. 如何选择?** - 使用 `CyclicBarrier`: 需要**固定数量线程的分阶段同步**,且逻辑简单(如分批处理数据)。 - 使用 `Phaser`: 需要**动态线程数**、**多阶段任务**或**复杂同步逻辑**(如动态扩展的任务流)。 --- ### **总结** - **CyclicBarrier**:简单、轻量,适合固定线程数的分批次同步。 - **Phaser**:功能强大,适合需要动态调整线程数多阶段协作的复杂场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值