问题描述
项目迁移到新的平台上后,已有的一个测试用例出现随机的失败,在老的平台上,已经运行了大半年,都是好好的,本地也是运行的好好的,very trick~~~.
没有办法,只能撸代码了。我们有一个功能,需要从不同的sever抓取数据,然后把数据聚合到map里面。为了加快响应速度,引入了线程池,代码如下:
// 查询后台可用的server列表
Set<Server> servers = this.serverService.getServers();
Executor executor = new DelegatingSecurityContextExecutor(ForkJoinPool.commonPool());
CompletionService<Object> completionService = new ExecutorCompletionService<>(executor);
// 提交task给completionService
servers.forEach(server -> completionService.submit(() -> this.doSearch(server));
// 获取结果,每次最大等待20s
for (int i = 0; i < servers.size(); i++) {
Future<Object> future = completionService.poll(20, TimeUnit.SECONDS);
if (!(future == null || future.isCancelled())) {
// 从future中获取结果
}
}
在单元测试用例中,设计了如下测试场景:mock 两个severs(server1, server2), 并且让server2在30s后才返回结果
//Server2 with 30s delay
BDDMockito.doAnswer(AdditionalAnswers.answersWithDelay(3000

项目迁移后,一个测试用例出现随机失败,原因是ForkJoinPool.commonPool只有一个线程,导致线程饥饿(Thread Starvation)。线程池大小由CPU核数决定,当超时任务占用线程时,短耗时任务无法及时执行。解决方案包括增加硬件资源或调整测试用例,确保短任务优先执行。问题关键在于提交给CompletionService的任务顺序不定,通过修改为TreeSet并定制比较器确保正确顺序。

1360

被折叠的 条评论
为什么被折叠?



