CountDownLatch并发测试实战应用案例
CountDownLatch在并发测试中模拟高并发场景,通过两个计数器解决线程同时启动和结果汇总问题:startLatch统一释放所有线程,doneLatch确保主线程等待全部请求完成后统计平均响应时间等指标,注意在finally中调用countDown避免阻塞。
CountDownLatch 在并发测试领域堪称经典利器,广泛应用于模拟真实的高并发压力场景,帮助开发人员精准计算接口的平均响应时间、吞吐量以及错误率等核心性能指标。它的核心目标在于攻克两个常见难题:第一,如何确保数十上百个线程真正实现“同时”发起请求,避免因线程调度的先后顺序造成启动时间偏差;第二,如何让主线程在所有请求处理完毕后统一汇总分析,防止由于数据不完整而得出错误的统计结论。

确保多线程真正并发启动
单纯通过 new Thread().start() 无法保证真正的“并发”——线程的创建与调度本身存在时序差异,先后启动的线程可能相差数毫秒甚至更长。CountDownLatch 在此处扮演“统一发令枪”的角色:
- 主线程首先创建一个
CountDownLatch startLatch = new CountDownLatch(1),充当统一的启动信号 - 每个工作线程启动后立即执行
startLatch.await(),使所有线程在同一个起跑线上等待 - 主线程完成所有线程的创建后,仅调用一次
startLatch.countDown(),瞬间唤醒所有等待的线程 - 通过这种方式,所有线程几乎在同一时间点(毫秒级)发起请求,真实模拟高并发压测场景
等待全部请求完成再统计结果
另一个关键问题是:主线程必须等待所有并发请求都返回之后,才能计算平均耗时、成功率等指标。此时需要第二个 CountDownLatch:
- 初始化
CountDownLatch doneLatch = new CountDownLatch(threadCount),用于跟踪所有线程的完成状态 - 每个工作线程在请求结束后(无论成功还是异常),必须执行
doneLatch.countDown()通知主线程 - 主线程调用
doneLatch.await(),推荐使用带超时参数的await(60, TimeUnit.SECONDS),防止个别请求卡死导致测试挂起 - 超时后主动中断尚未完成的线程,同时将超时数纳入统计,提升测试的鲁棒性和准确度
组合使用两个Latch实现完整压测流程
以下是一个典型的并发测试实现示例,展示了两个 CountDownLatch 的组合用法:
int threadCount = 100; CountDownLatch startLatch = new CountDownLatch(1); CountDownLatch doneLatch = new CountDownLatch(threadCount); Listdurations = Collections.synchronizedList(new ArrayList<>()); for (int i = 0; i < threadCount; i++) { new Thread(() -> { try { startLatch.await(); // 等待统一开始信号 long start = System.nanoTime(); // 执行实际业务请求,例如HTTP调用 doHttpRequest(); long end = System.nanoTime(); durations.add((end - start) / 1_000_000); // 毫秒 } catch (Exception e) { // 捕获异常,确保最终执行countDown以完成统计 } finally { doneLatch.countDown(); } }).start(); } // 所有线程就绪后,触发并发启动 startLatch.countDown(); // 主线程等待所有请求完成,设置60秒超时 doneLatch.await(60, TimeUnit.SECONDS); // 统计结果 double a vg = durations.stream().mapToLong(Long::longValue).a verage().orElse(0.0); System.out.println("平均响应时间:" + a vg + " ms");
注意避免常见陷阱
编写测试代码时,以下细节尤其容易出现问题:
- 每个线程必须严格只调用一次
countDown()—— 如果某个线程误调多次,会导致计数器提前归零,主线程过早退出,从而遗漏部分请求的统计数据 - 强烈建议在
finally块中调用countDown()—— 即使请求抛出异常或超时,也要确保计数器递减,否则await()将永久阻塞,测试进程被挂死 - 切勿复用已归零的 CountDownLatch 实例 —— 它是一次性同步工具,下次测试必须创建新实例;如需循环使用,建议改用
CyclicBarrier - 避免在主线程中同时使用
join()和await()—— 两者功能重叠且语义复杂,推荐统一使用 CountDownLatch 进行线程协调,代码逻辑更清晰
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
IDEA中SpringBoot项目热部署实现指南
Springboot项目在IDEA中实现热部署需依次完成:开启自动编译(静态与动态编译)、启用热部署策略、引入spring-boot-devtools依赖、关闭浏览器缓存,最后启动测试即可生效,省去手动重启时间,大幅提升开发效率。
Java实现Excel转JSON的代码详解
使用Java结合FreeSpire XLS库可自动将Excel转为JSON,通过读取工作表并映射为键值对,高效支持数据迁移、报表导出与系统对接,大幅提升效率并消除手动录入错误。
Golang高效布谷鸟过滤器多字符集字符串过滤
布谷鸟过滤器支持删除操作,通过指纹截断与双哈希定位实现多字符集高效过滤。指纹截断需采用fnv64a或xxhash快速哈希并取低8位,桶索引使用独立双哈希避免假阳性。并发安全需以固定数组配合sync atomic实现。
Java使用Poi-tl按Word模板生成动态表格
Poi-tl是Word导出工具,文档周全,支持多级合并表头生成。通过{{text}}、{{?var}}、{{ table}}标签处理模板,传入TableRenderData对象即可动态渲染表格。示例展示用户信息表格生成,并提供工具类消除表格首行缩进,确保格式正确。
Go语言微服务集成Swagger生成交互式API文档完整教程
在Go微服务中集成Swagger常见四大问题:swaginit初始化失败需确保存在packagemain及注释;SwaggerUI加载失败因路由映射错误或未导入docs;@Param注解必须严格遵循格式;部署后接口文档显示localhost因硬编码host,应删除或通过环境变量动态注入。
- 热门数据榜
相关攻略
2026-07-11 06:47
2026-07-11 06:47
2026-07-11 06:47
2026-07-11 06:47
2026-07-11 06:47
2026-07-11 06:46
2026-07-11 06:46
2026-07-11 06:46
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

