概述
最近写一个批量业务接口,为了降低响应时间,遂使用了自定义线程池
+ CompletableFuture
异步执行任务,阻塞获取结果,
但在测试过程中,发现一个很奇怪的问题
下面造一个测试案例来复现问题,也方便带大家了解~
问题案例
@SpringBootTest
public class OtherTest {
@Resource
private ThreadPoolExecutor threadPoolExecutor;
@Test
public void test() {
List<Integer> list = new ArrayList<>(100);
for (int i = 0; i < 100; i++) {
list.add(i);
}
List<CompletableFuture<Integer>> futureList = list.stream().map(num -> {
return CompletableFuture.supplyAsync(() -> {
// 模拟业务
return num + 1;
}, threadPoolExecutor);
}).collect(Collectors.toList());
CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).join();
for (CompletableFuture<Integer> completableFuture : futureList) {
try {
System.out.println(completableFuture.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
复制代码
执行案例后,我们会发现主线程一直被阻塞,下面的打印根本没有执行!这 就是我遇到的问题
为啥被阻塞了?
我们直接Dump Threads
,可以看到主线程处于WAITING
状态,通过堆栈跟踪,我们可以看到是被LockSupport.park
了
因为我们最终会CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).join();
阻塞获取结果
根据join
方法一路跟踪,最终到达java.util.concurrent.CompletableFuture.Signaller#block
,也符合上图的堆栈信息
ok,问题算是找到了,但是为啥会一直阻塞呢