以实际案例说明CountDownLatch和CyclicBarrier的使用场景

以实际案例说明CountDownLatch和CyclicBarrier的使用场景

我来用两个生动的实际案例来说明CountDownLatch和CyclicBarrier的使用场景。

案例1:使用CountDownLatch的电商订单处理系统

场景描述

想象一个电商平台的订单处理流程。当用户下单时,系统需要完成多个独立的任务才能确认订单:库存检查、支付验证、优惠券验证、物流信息校验等。主线程需要等待所有这些验证都完成才能继续处理。

代码实现

public class OrderProcessingSystem {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个CountDownLatch,计数值为4(表示4个验证任务)
        CountDownLatch orderLatch = new CountDownLatch(4);
        
        System.out.println("开始处理订单...");
        long startTime = System.currentTimeMillis();

        // 启动库存检查线程
        new Thread(() -> {
            try {
                Thread.sleep(2000); // 模拟检查耗时
                System.out.println("库存检查完成,库存充足");
                orderLatch.countDown(); // 完成一个任务,计数减1
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "库存检查线程").start();

        // 启动支付验证线程
        new Thread(() -> {
            try {
                Thread.sleep(3000); // 模拟验证耗时
                System.out.println("支付验证完成,支付成功");
                orderLatch.countDown();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "支付验证线程").start();

        // 启动优惠券验证线程
        new Thread(() -> {
            try {
                Thread.sleep(1500); // 模拟验证耗时
                System.out.println("优惠券验证完成,优惠券有效");
                orderLatch.countDown();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "优惠券验证线程").start();

        // 启动物流信息校验线程
        new Thread(() -> {
            try {
                Thread.sleep(1000); // 模拟校验耗时
                System.out.println("物流信息校验完成,可以配送");
                orderLatch.countDown();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "物流校验线程").start();

        // 主线程等待所有验证任务完成
        orderLatch.await();
        
        long endTime = System.currentTimeMillis();
        System.out.println("所有验证任务已完成,订单处理成功!");
        System.out.println("总耗时:" + (endTime - startTime) + "ms");
    }
}

运行输出示例

开始处理订单...
物流信息校验完成,可以配送
优惠券验证完成,优惠券有效
库存检查完成,库存充足
支付验证完成,支付成功
所有验证任务已完成,订单处理成功!
总耗时:3024ms

案例2:使用CyclicBarrier的大数据批处理系统

场景描述

想象一个需要处理大量数据的系统,比如一个日志分析系统。我们需要多个线程并行处理数据,每个线程负责一部分数据。处理完一批数据后,需要等待所有线程都完成才能进行数据汇总,然后继续处理下一批数据。

代码实现

public class LogAnalysisSystem {
    public static void main(String[] args) {
        int threadCount = 3; // 3个工作线程
        int batchSize = 1000; // 每批处理1000条日志
        AtomicInteger totalProcessedLogs = new AtomicInteger(0);
        
        // 创建CyclicBarrier,所有线程到达后执行汇总任务
        CyclicBarrier barrier = new CyclicBarrier(threadCount, () -> {
            System.out.println("\n=== 当前批次所有数据处理完成 ===");
            System.out.println("已处理总日志数:" + totalProcessedLogs.get());
            System.out.println("开始处理下一批数据...\n");
        });

        // 启动工作线程
        for (int i = 0; i < threadCount; i++) {
            final int threadId = i + 1;
            new Thread(() -> {
                try {
                    // 模拟处理多批数据
                    for (int batch = 1; batch <= 3; batch++) {
                        // 模拟处理一批数据
                        int processedCount = processLogsInBatch(threadId, batchSize);
                        totalProcessedLogs.addAndGet(processedCount);
                        
                        System.out.printf("线程%d完成第%d批数据处理,本批处理%d条日志\n", 
                                        threadId, batch, processedCount);
                        
                        // 等待其他线程完成当前批次
                        barrier.await();
                    }
                } catch (InterruptedException | BrokenBarrierException e) {
                    Thread.currentThread().interrupt();
                }
            }, "工作线程-" + threadId).start();
        }
    }

    // 模拟处理一批日志的方法
    private static int processLogsInBatch(int threadId, int batchSize) throws InterruptedException {
        // 模拟处理时间
        Thread.sleep((long) (Math.random() * 2000));
        // 返回实际处理的日志数量
        return (int) (batchSize * (0.8 + Math.random() * 0.4));
    }
}

运行输出示例

线程1完成第1批数据处理,本批处理923条日志
线程2完成第1批数据处理,本批处理1012条日志
线程3完成第1批数据处理,本批处理967条日志

=== 当前批次所有数据处理完成 ===
已处理总日志数:2902
开始处理下一批数据...

线程2完成第2批数据处理,本批处理889条日志
线程1完成第2批数据处理,本批处理945条日志
线程3完成第2批数据处理,本批处理978条日志

=== 当前批次所有数据处理完成 ===
已处理总日志数:5714
开始处理下一批数据...

关键区别总结

CountDownLatch(订单处理案例)适用场景

  • 一次性的等待场景。
  • 主线程等待多个子任务完成。
  • 任务之间相对独立。
  • 不需要重复使用的场景。

CyclicBarrier(日志分析案例)适用场景

  • 需要循环处理的场景。
  • 多个线程需要相互等待。
  • 处理完一个阶段后,需要进行汇总或同步。
  • 需要重复使用的场景。

通过这两个实际的案例,我们可以看到:

  • CountDownLatch更像是“等待结束”的工具,适合主线程等待多个任务完成的场景。
  • CyclicBarrier更像是“集合点”的工具,适合多个线程之间互相等待,且需要多次重复的场景。

这样理解起来是不是更清晰了?如果你还有任何疑问,欢迎评论区留言讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值