一、快速上手 CompletableFuture
1. 一个简单的 CompletableFuture Demo
CompletableFuture<Integer> test=CompletableFuture.supplyAsync(()-> func());
其中,func()
是一个返回值为Integer的函数。
我们可以通过join()
方法来获取 func() 的返回值。
//这里可以运行其他的代码
Integer num=test.join();
此时这个 num 值,就是我们通过异步来获取的。这里我们就完成了最简单的 CompletableFuture 的使用案例。
到这里,肯定会有人觉得,就这?
别着急,到这里我们能确定一个事情——这里启动了另外一个线程来进行异步处理。最后通过
join()
来获取另外一个线程的处理结果。
由此,今天很重要的两个问题产生了
- 另外一个线程哪里来的?
join()
的时候另外一个线程没有处理完会发生什么?
让我们来一步一步的解决这两个问题
2.CompletableFuture 初始化参数
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(ASYNC_POOL, supplier);
}
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor) {
return asyncSupplyStage(screenExecutor(executor), supplier);
}
public static CompletableFuture<Void> runAsync(Runnable runnable) {
return asyncRunStage(ASYNC_POOL, runnable);
}
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) {
return asyncRunStage(screenExecutor(executor), runnable);
}
从上面的源码中可以看出 CompletableFuture 提供了四个初始化的方法,runAsync
和 supplyAsync
分别提供了 Runnable
和 Supplier<U>
的参数选择。同时,还提供了带线程池参数的方法,可以指定线程池。
//使用默认线程池
static CompletableFuture<Void>
runAsync(Runnable runnable)
static <U> CompletableFuture<U>
supplyAsync(Supplier<U> supplier)
//可以指定线程池
static CompletableFuture<Void>
runAsync(Runnable runnable, Executor executor)
static <U> CompletableFuture<U>
supplyAsync(Supplier<U> supplier, Executor executor)
而不带线程池的创建方法,使用了名为 ASYNC_POOL
的线程池。
我们打上断点,看下线程池是从哪里来的。
我们可以看到他使用 ForkJoinPool 的线程池。
ASYNC_POOL = (Executor)(USE_COMMON_POOL ? ForkJoinPool.commonPool() : new CompletableFuture.ThreadPerTaskExecutor());
3.join 方法
join 方法和 Future 接口中的 get 方法有相同的含义,并
且也声明在 Future 接口中,它们唯一的区别是 CompletableFuture 的 join()
不会抛出任何检测到的异常。因此此时如果 join()
没有处理完,并不会抛出任何异常。
二、CompletableFuture 提供的方法
除了我们上面说到的 join()
CompletableFuture 还提供了,像方法
三、CompletableFuture 其他用法
1.在stream 中使用 CompletableFuture
List<CompletableFuture<String>> priceFutures =
shops.stream()
.map(shop -> CompletableFuture.supplyAsync(
() -> shop.getName() + " price is " +
shop.getPrice(product)))
.collect(Collectors.toList());
return priceFutures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
四、总结
- CompletableFuture 使用时最好指定线程池。不指定默认会使用 ForkJoinPool 作为线程池。当然如果 CPU 数量小于 2 会直接 new Thread ,这会导致 FULL GC 问题。
- join 方法不会报错,但是会阻塞 join 后面的任务
评论区