侧边栏壁纸
博主头像
ProSayJ 博主等级

Talk is cheap. Show me the code.

  • 累计撰写 72 篇文章
  • 累计创建 24 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

CountDownLatch、CyclicBarrier、Semaphore区别

YangJian
2025-07-14 / 0 评论 / 0 点赞 / 3 阅读 / 0 字

✅ 一、核心区别总结表

特性 / 类名

CountDownLatch

CyclicBarrier

Semaphore

作用

让一个或多个线程等待其他线程完成

让一组线程在到达屏障点后一起执行

控制同时访问某资源的线程数量

是否可重用

❌ 一次性使用

✅ 可循环使用

✅ 可重复使用

底层机制

基于 AQS 的共享锁,内部计数器

基于 ReentrantLock + Condition

基于 AQS 共享资源许可机制(permits)

常见应用

等待多个线程初始化、任务完成、批处理

并发任务分段同步、游戏多人就位后开始

限流、连接池、访问控制等场景

构造方法

new CountDownLatch(int count)

new CyclicBarrier(int parties)

new Semaphore(int permits)

唤醒机制

countDown() 次数为 0 时释放 await 阻塞线程

所有线程调用 await() 到达屏障,全部放行

获取资源 acquire() / 释放资源 release()


✅ 二、代码举例 + 输出说明

✅ 1️⃣ CountDownLatch 示例

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3); // 等待3个线程完成

        for (int i = 0; i < 3; i++) {
            final int no = i;
            new Thread(() -> {
                System.out.println("线程 " + no + " 执行完成");
                latch.countDown();
            }).start();
        }

        latch.await(); // 主线程等待所有子线程完成
        System.out.println("所有子线程已完成,主线程继续执行");
    }
}

🟢 输出示例:

线程 0 执行完成
线程 1 执行完成
线程 2 执行完成
所有子线程已完成,主线程继续执行

✅ 2️⃣ CyclicBarrier 示例

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(
                3, () ->
                System.out.println("所有线程到达屏障点,统一出发"));
        for (int i = 0; i < 6; i++) {
            final int no = i;
            new Thread(() -> {
                try {
                    System.out.println("线程 " + no + " 到达屏障点");
                    barrier.await(); // 等待其他线程到达
                    System.out.println("线程 " + no + " 继续执行");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

🟢 输出示例:

线程 0 到达屏障点
线程 1 到达屏障点
线程 2 到达屏障点
所有线程到达屏障点,统一出发
线程 2 继续执行
线程 0 继续执行
线程 1 继续执行
线程 3 到达屏障点
线程 4 到达屏障点
线程 5 到达屏障点
所有线程到达屏障点,统一出发
线程 5 继续执行
线程 3 继续执行
线程 4 继续执行

✅ 3️⃣ Semaphore 示例

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2); // 同时最多2个线程访问
        for (int i = 0; i < 5; i++) {
            final int no = i;
            new Thread(() -> {
                try {
                    semaphore.acquire(); // 尝试获取许可
                    System.out.println("线程 " + no + " 获取许可,开始执行");
                    Thread.sleep(1000); // 模拟执行任务
                    System.out.println("线程 " + no + " 执行完毕,释放许可");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();
                }
            }).start();
        }
    }
}

🟢 输出示例(两个一组执行):

线程 0 获取许可,开始执行
线程 1 获取许可,开始执行
线程 0 执行完毕,释放许可
线程 4 获取许可,开始执行
线程 1 执行完毕,释放许可
线程 2 获取许可,开始执行
线程 4 执行完毕,释放许可
线程 2 执行完毕,释放许可
线程 3 获取许可,开始执行
线程 3 执行完毕,释放许可

0

评论区