countdownlatch结合项目,什么场景使用?

1 个回答

  • 妲己
    上了生活的贼船,就要做快乐的海盗。
    `CountDownLatch` 是 **Java 并发工具类**,用于 **等待多个任务完成后再继续执行**,主要应用于**任务同步、并发控制**等场景。 ## **1. 适用场景** ### **场景 1:多个子任务执行完毕后,主任务继续执行** 在一些复杂计算任务中,可能需要**多个子任务并行执行**,当所有子任务都完成后,主任务才能继续。例如: 🔹 **项目案例:并行数据处理** 假设一个数据处理任务需要从 **多个数据库表** 读取数据并汇总,我们可以使用 `CountDownLatch` 让主线程等待所有数据读取完毕再执行汇总操作。 ```java import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class DataProcessing { public static void main(String[] args) throws InterruptedException { int taskCount = 3; CountDownLatch latch = new CountDownLatch(taskCount); ExecutorService executor = Executors.newFixedThreadPool(taskCount); for (int i = 1; i <= taskCount; i++) { final int taskId = i; executor.submit(() -> { try { System.out.println("任务 " + taskId + " 读取数据中..."); Thread.sleep(2000); // 模拟数据读取 System.out.println("任务 " + taskId + " 读取数据完成"); } catch (InterruptedException e) { e.printStackTrace(); } finally { latch.countDown(); // 任务完成,减少计数 } }); } latch.await(); // 等待所有任务完成 System.out.println("所有任务执行完毕,开始数据汇总..."); executor.shutdown(); } } ``` ✅ **适用场景** - **多个数据源的数据同步** - **并行日志分析,待所有日志分析完再汇总** - **多个 HTTP 请求,等待所有请求返回后进行处理** ### **场景 2:主线程等待多个子线程初始化完成** 在一些应用程序启动过程中,可能需要**多个组件完成初始化**后才能正式对外提供服务。 🔹 **项目案例:系统启动时等待多个模块初始化** ```java import java.util.concurrent.CountDownLatch; public class SystemStartup { public static void main(String[] args) throws InterruptedException { int serviceCount = 3; CountDownLatch latch = new CountDownLatch(serviceCount); new Thread(new ServiceInitTask("数据库", latch)).start(); new Thread(new ServiceInitTask("缓存", latch)).start(); new Thread(new ServiceInitTask("消息队列", latch)).start(); latch.await(); // 等待所有服务初始化完成 System.out.println("所有服务已启动,系统启动完成!"); } static class ServiceInitTask implements Runnable { private final String serviceName; private final CountDownLatch latch; ServiceInitTask(String serviceName, CountDownLatch latch) { this.serviceName = serviceName; this.latch = latch; } @Override public void run() { try { System.out.println(serviceName + " 服务初始化中..."); Thread.sleep(3000); // 模拟初始化时间 System.out.println(serviceName + " 服务初始化完成!"); } catch (InterruptedException e) { e.printStackTrace(); } finally { latch.countDown(); } } } } ``` ✅ **适用场景** - **微服务启动时等待多个依赖服务(如数据库、缓存)初始化** - **Spring Boot 服务启动时等待所有组件加载完毕** - **游戏服务器等待多个模块(如地图、角色、网络通信)加载完毕后再允许玩家进入** ### **场景 3:并发性能测试** 在性能测试或压测场景下,希望**多个线程同时开始执行任务**,以模拟并发访问。例如,模拟 **100 个用户同时访问网站**。 🔹 **项目案例:模拟高并发请求** ```java import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ConcurrentTest { public static void main(String[] args) throws InterruptedException { int userCount = 10; CountDownLatch startSignal = new CountDownLatch(1); CountDownLatch doneSignal = new CountDownLatch(userCount); ExecutorService executor = Executors.newFixedThreadPool(userCount); for (int i = 0; i < userCount; i++) { executor.submit(() -> { try { startSignal.await(); // 等待开始信号 System.out.println(Thread.currentThread().getName() + " 开始访问网站..."); Thread.sleep((long) (Math.random() * 2000)); // 模拟请求延迟 System.out.println(Thread.currentThread().getName() + " 访问结束"); } catch (InterruptedException e) { e.printStackTrace(); } finally { doneSignal.countDown(); } }); } System.out.println("所有用户准备完毕,开始并发测试!"); startSignal.countDown(); // 释放所有线程 doneSignal.await(); // 等待所有请求完成 System.out.println("所有用户请求完成,测试结束!"); executor.shutdown(); } } ``` ✅ **适用场景** - **模拟大量用户同时访问接口** - **网站压力测试** - **支付系统高并发请求模拟** ## **4. `CountDownLatch` 的优缺点** | **优点** | **缺点** | |---------|---------| | 线程间同步简单,代码可读性高 | `CountDownLatch` **一次性使用**,不能重置计数 | | 可用于**并发任务控制**,适合需要等待多个线程完成的场景 | **不支持增加计数**(只能递减,不能递增) | | 避免了 `Thread.sleep()` 带来的不确定性 | 无法复用,需要创建新的 `CountDownLatch` | ## **5. `CountDownLatch` vs `CyclicBarrier` vs `Semaphore`** | **工具** | **用途** | **主要特点** | |---------|--------|------------| | `CountDownLatch` | **等待一组任务完成** | **一次性**,计数只能减少,不能重置 | | `CyclicBarrier` | **一组线程互相等待,然后一起执行** | **可循环使用**,适用于 **固定数量线程的同步** | | `Semaphore` | **限制并发访问数量** | 适用于 **限流**,可设置**多个线程同时访问** | ## **6. 总结** ### **适用场景** - **多个任务完成后,主任务继续执行** - **系统启动时,等待多个组件初始化** - **模拟并发访问,性能测试** - **需要线程同步,但不想引入锁(synchronized)的性能开销** ### **使用建议** - **任务计数固定**,适合使用 `CountDownLatch` - **任务计数不固定,需要重复使用**,考虑 `CyclicBarrier` - **限流、并发控制**,使用 `Semaphore` **✅ 结论:`CountDownLatch` 适用于** 等待 **一组线程任务完成**,然后**继续执行主线程**,是 Java 并发编程中的重要工具。
    编辑于 2025-03-23 18:08 •IP属地 美国
    举报
    评论
    收藏