CyclicBarrier、CountDownLatch、Semaphore 各自的作用和用法区别

它们都是 java.util.concurrent 包下用于线程协作的强大工具,但各自的设计目的和使用场景截然不同。你可以把它们想象成交通管理工具:

  • CountDownLatch :像一个 发令枪。所有运动员(线程)在起跑线等待,枪响(计数器归零)后同时开始。
  • CyclicBarrier :像一个 集合点。一组远足的人(线程)必须全部到达某个地点后,才能一起继续前进。
  • Semaphore :像一个 票务系统。一个停车场只有有限的车位(许可),有车(线程)离开,才有新车可以进入。

下面我们进行详细的对比。


1. CountDownLatch(倒计时门闩)

核心作用让一个或多个线程等待另一组线程完成操作。它是一次性的,计数器不能被重置。

工作机制

  1. 初始化时设定一个计数值(比如 N)。
  2. 任何线程可以调用 countDown() 方法来减少计数。
  3. 其他线程调用 await() 方法会阻塞,直到计数值减到零,所有等待的线程才会被释放,继续执行。

典型用法

  • 主线程等待多个子线程初始化完成后再继续执行。
  • 模拟并发测试,确保所有线程都准备就绪后同时开始运行。
  • 等待多个远程服务调用结束后再进行结果聚合。

代码示例

// 主线程等待 5 个工作线程全部完成

java 复制代码
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(5); // 初始化计数器为5

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " 完成任务");
                latch.countDown(); // 计数器减1
            }).start();
        }

        latch.await(); // 主线程在此等待,直到计数器变为0
        System.out.println("所有线程已完成任务,主线程继续执行");
    }
}

2. CyclicBarrier(循环屏障)

核心作用让一组线程互相等待,直到所有线程都到达一个公共的屏障点,然后一起继续执行。它是可循环使用的。

工作机制

  1. 初始化时设定一个计数值(参与线程数 N)和一个可选的 Runnable 任务(屏障动作)。
  2. 每个线程执行到屏障点时调用 await() 方法,该方法会阻塞。
  3. 当第 N 个线程调用 await() 后,计数达到要求,所有被阻塞的线程会被同时唤醒继续执行 ,并且计数器自动重置到初始值,可以再次使用。
  4. 可选的 Runnable 屏障任务会在所有线程被唤醒前,由最后一个到达屏障的线程执行。

典型用法

  • 分步计算任务,将一个大任务分成N个小任务,每个线程处理一部分,最后在屏障点合并结果。
  • 多轮游戏或模拟,需要所有玩家都准备好才开始下一轮。

代码示例

// 3个线程一起到一个屏障点集合,然后继续

java 复制代码
public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(3, () -> {
            // 屏障动作,由最后到达的线程执行
            System.out.println("所有线程已就位,开始执行下一步任务");
        });

        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " 到达屏障前");
                    barrier.await(); // 在此等待其他线程
                    System.out.println(Thread.currentThread().getName() + " 冲破屏障,继续执行");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

3. Semaphore(信号量)

核心作用控制同时访问某个特定资源的线程数量,用于做流量控制或资源池管理。

工作机制

  1. 初始化时设定一个许可数量permits)。
  2. 线程通过 acquire() 方法获取一个许可(如果还有可用许可),许可数量减1。
  3. 如果许可已被拿完,后续调用 acquire() 的线程会被阻塞,直到有其他线程释放许可
  4. 线程使用完资源后,通过 release() 方法释放许可,许可数量加1,并唤醒一个等待的线程。

典型用法

  • 数据库连接池,限制同时获取连接的线程数。
  • 流量控制,如限制某个接口的并发调用数。
  • 控制访问特定设备的线程数(如打印机)。

代码示例

// 一个只有3个许可的信号量,控制同时执行的线程数

java 复制代码
public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3); // 初始化3个许可

        for (int i = 0; i < 10; i++) { // 启动10个线程
            new Thread(() -> {
                try {
                    semaphore.acquire(); // 获取许可
                    System.out.println(Thread.currentThread().getName() + " 获取许可,执行中...");
                    Thread.sleep(2000); // 模拟业务操作
                    System.out.println(Thread.currentThread().getName() + " 执行完毕,释放许可");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release(); // 释放许可
                }
            }).start();
        }
    }
}

总结对比表

特性 CountDownLatch CyclicBarrier Semaphore
核心目的 一个/多个线程等待其他线程完成 一组线程互相等待至一个公共点 控制同时访问资源的线程数
计数器 递减(countDown()),一次性 递增(await()),可循环重置 递减(acquire())/递增(release())
可重用性 不可重用(计数到0后失效) 可重用(自动重置计数器) 可重用(许可可重复获取和释放)
主要方法 await(), countDown() await() acquire(), release()
计数操作 任意线程减少计数 等待的线程自身增加计数 需要访问资源的线程获取和释放
典型场景 主等子、启动发令枪 多步骤任务同步、多轮协作 资源池、流量控制、互斥锁(Permits=1)
相关推荐
身如柳絮随风扬5 分钟前
Java中的CAS机制详解
java·开发语言
韩立学长1 小时前
【开题答辩实录分享】以《基于Python的大学超市仓储信息管理系统的设计与实现》为例进行选题答辩实录分享
开发语言·python
风筝在晴天搁浅1 小时前
hot100 78.子集
java·算法
froginwe112 小时前
Scala 循环
开发语言
m0_706653232 小时前
C++编译期数组操作
开发语言·c++·算法
故事和你912 小时前
sdut-Java面向对象-06 继承和多态、抽象类和接口(函数题:10-18题)
java·开发语言·算法·面向对象·基础语法·继承和多态·抽象类和接口
Bruk.Liu2 小时前
(LangChain实战2):LangChain消息(message)的使用
开发语言·langchain
qq_423233902 小时前
C++与Python混合编程实战
开发语言·c++·算法
m0_715575343 小时前
分布式任务调度系统
开发语言·c++·算法
Configure-Handler3 小时前
buildroot System configuration
java·服务器·数据库