一、CompletableFuture allOf的优点
场景:当有一批任务交给线程池执行,我们需要获取所有线程的返回结果。
- Future的get()时阻塞的,如果循环get()每一个线程的结果,一个线程会卡住后面所有线程
- CompletionService的take().get()虽然不会因为某个线程阻塞后面的线程,但是功能不丰富
- CompletableFuture提供的功能丰富,使用简单,代码优雅
- Java9中CompletableFuture还添加了completeOnTimeout、orTimeout,方便对超时任务的处理
二、测试案例
- 一串数字1, 2, 3, 4, 5, 6, 7, 8, 9, 10
- 开启线程,执行乘以2的计算
- 其中任务2会抛出异常
- 要获取所有线程的返回结果和异常结果
这里用到之前学的handle来处理线程的结果
public class Thread17_AllOf {
public static void main(String[] args) {
//记录开始时间
Long start = System.currentTimeMillis();
//定长10线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
//任务
List<Integer> taskList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<String> resultList = Collections.synchronizedList(new ArrayList<>());
Map<String, String> errorList = new ConcurrentHashMap<>();
Stream<CompletableFuture<String>> completableFutureStream = taskList.stream()
.map(num -> {
return CompletableFuture
.supplyAsync(() -> {
return getDouble(num);
},
executor)
.handle(new BiFunction<Integer, Throwable, String>() {
@Override
public String apply(Integer s, Throwable throwable) {
if (throwable == null) {
System.out.println("任务" + num + "完成! result=" + s + ", " + new Date());
resultList.add(s.toString());
} else {
System.out.println("任务" + num + "异常! e=" + throwable + ", " + new Date());
errorList.put(num.toString(), throwable.getMessage());
}
return "";
}
});
}
);
CompletableFuture[] completableFutures = completableFutureStream.toArray(CompletableFuture[]::new);
CompletableFuture.allOf(completableFutures)
.whenComplete((v, th) -> {
System.out.println("所有任务执行完成触发\n resultList=" + resultList + "\n errorList=" + errorList+ "\n耗时=" + (System.currentTimeMillis() - start));
}).join();
System.out.println("end");
}
//根据数字判断线程休眠的时间
public static Integer getDouble(Integer i) {
try {
if (i == 1) {
//任务1耗时3秒
Thread.sleep(3000);
} else if (i == 2) {
//任务2耗时1秒,还出错
Thread.sleep(1000);
throw new RuntimeException("出异常了");
} else {
//其它任务耗时1秒
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return 2 * i;
}
}
任务3完成! result=6, Fri May 07 16:52:27 CST 2021
任务2异常! e=java.util.concurrent.CompletionException: java.lang.RuntimeException: 出异常了, Fri May 07 16:52:27 CST 2021
任务4完成! result=8, Fri May 07 16:52:28 CST 2021
任务5完成! result=10, Fri May 07 16:52:28 CST 2021
任务1完成! result=2, Fri May 07 16:52:29 CST 2021
任务6完成! result=12, Fri May 07 16:52:29 CST 2021
任务7完成! result=14, Fri May 07 16:52:29 CST 2021
任务8完成! result=16, Fri May 07 16:52:30 CST 2021
任务10完成! result=20, Fri May 07 16:52:30 CST 2021
任务9完成! result=18, Fri May 07 16:52:30 CST 2021
所有任务执行完成触发
resultList=[6, 8, 10, 2, 12, 14, 16, 20, 18]
errorList={2=java.lang.RuntimeException: 出异常了}
耗时=4097
end