Java1.5引入了Future,在1.8中又引入了CompletableFuture。他的出现可以使我们更好的去对任务进行编排,合理的使用会极大的缩减多任务的处理时间,达到事半功倍的目的。下面让我们一块来看一下与它相关的一些知识。
1 Java中的函数式编程
在看CompletableFuture了解一点Java中函数式编程相关的知识会更有用一些。
在Java1.8中引入了@FunctionalInterface
,同时也在java.util.function
包中引入了很多函数式接口。我们来看几个常见的:
1.1 Consumer
Consumer消费者,关联的方法为void accept(T t)
,有参无返回值。
@FunctionalInterface
public interface Consumer {
void accept(T t);
1.2 Function
Function函数,关联方法为R apply(T t)
,有参有返回值。
@FunctionalInterface
public interface Function {
R apply(T t);
1.3 Predicate
Predicate谓语(断言?),关联方法为boolean test(T t)
,有参有返回值(bool)。
@FunctionalInterface
public interface Predicate {
boolean test(T t);
1.4 Supplier
Supplier供应者,关联方法为T get()
,无参有返回值。
@FunctionalInterface
public interface Supplier {
T get();
}
2 CompletableFuture
后续的内容主要关注点会放在其内部各种API上面。在后续的方法中,因为CompletableFuture
实现了CompletionStage
使其具有链式调用能力。大多数方法都会类似如下:
- xxx(Function func): 会上文的
同一线程
去执行当前任务 - xxxAsync(Function func): 会启用一个
新线程
去执行当前任务 - xxxAsync(Function func, Executor executor): 会使用
executor
线程池中的新线程
去执行当前任务
2.1 CompletableFuture的创建
supplyAsync
: 以Supplier
为参,有返回值。
public static CompletableFuture supplyAsync(Supplier supplier)
public static CompletableFuture supplyAsync(Supplier supplier, Executor executor)
runAsync
: 以Runnable
为参,返回值为Void
。
public static CompletableFuture runAsync(Runnable runnable)
public static CompletableFuture runAsync(Runnable runnable, Executor executor)
completedFuture
: 创建一个已有值且完成的CompletableFuture。
public static CompletableFuture completedFuture(U value)
failedFuture
: 创建一个已出现异常且完成的CompletableFuture。
public static CompletableFuture failedFuture(Throwable ex)
可以看到runAsync
和supplyAsync
都提供了额外参数Executor
,在未指定executor
时,默认会使用ForkJoinPool.commonPool()
来执行异步任务,而Parallel Stream
默认情况下也会使用该线程池,共用的话可能会导致非核心业务抢占核心业务的执行。一般来说都会使用自定义线程池来执行这些任务。
2.2 CompletableFuture的后续操作
2.2.1 执行一个任务(1)
apply
: 有参有返回值。会将前面的返回值作为当前函数的输入。
public CompletableFuture thenApply(Function super T,? extends U> fn)
public CompletableFuture thenApplyAsync(Function super T,? extends U> fn)
public CompletableFuture thenApplyAsync(Function super T,? extends U> fn, Executor executor)
accept
: 有参无返回值。会将前面的输出作为当前函数的输入。
public CompletableFuture thenAccept(Consumer super T> action)
public CompletableFuture thenAcceptAsync(Consumer super T> action)
public CompletableFuture thenAcceptAsync(Consumer super T> action, Executor executor)
run
: 编排执行另外一个毫无相关的任务
public CompletableFuture thenRun(Runnable action)
public CompletableFuture thenRunAsync(Runnable action)
public CompletableFuture thenRunAsync(Runnable action, Executor executor)
示例
@Test
void testApply() throws ExecutionException, InterruptedException {
final CompletableFuture future = CompletableFuture
.supplyAsync(() -> 1)
.thenApply((val) -> val + 1);
assertEquals(2, future.get());
}
@Test
void testAccept() {
final CompletableFuture future = CompletableFuture
.supplyAsync(() -> 1)
.thenAccept((val) -> {
assertEquals(1, val);
});
future.join();
}
@Test
void testRun() {
final CompletableFuture future = CompletableFuture
.supplyAsync(() -> 1)
.thenRun(() -> {});
future.join();
}
2.2.1 执行一个任务(2)
whenComplete
: 当任务完成时执行该方法,将返回值及异常传入BiConsumer
(有参无返回值)
public CompletableFuture whenComplete(BiConsumer super T, ? super Throwable> action)
public CompletableFuture whenCompleteAsync(BiConsumer super T, ? super Throwable> action)
public CompletableFuture whenCompleteAsync(BiConsumer super T, ? super Throwable> action, Executor executor)
exceptionally
: 当相应的任务出现异常时会调用该方法,将异常作为参数传进来
public CompletableFuture exceptionally(Function fn)
public CompletableFuture exceptionallyAsync(Function fn)
public CompletableFuture exceptionallyAsync(Function fn, Executor executor)
handler
: 接收处理前面任务的结果BiFunction
(有参有返回值)
public CompletableFuture handle(BiFunction super T, Throwable, ? extends U> fn)
public CompletableFuture handleAsync(BiFunction super T, Throwable, ? extends U> fn)
public CompletableFuture handleAsync(BiFunction super T, Throwable, ? extends U> fn, Executor executor)
2.2.2 执行两个任务其中一个即可
applyToEither
: 执行俩任务,返回其中一个未出现异常的,并将该输出作为参数传入后续Function
(有参有返回值)
public CompletableFuture applyToEither(CompletionStage extends T> other, Function super T, U> fn)
public CompletableFuture applyToEitherAsync(CompletionStage extends T> other, Function super T, U> fn)
public CompletableFuture applyToEitherAsync(CompletionStage extends T> other, Function super T, U> fn, Executor executor)
acceptEither
: 执行俩任务,返回其中一个未出现异常的,并将该输出作为参数传入后续Consumer
(有参无返回值)
public CompletableFuture acceptEither(CompletionStage extends T> other, Consumer super T> action)
public CompletableFuture acceptEitherAsync(CompletionStage extends T> other, Consumer super T> action)
public CompletableFuture acceptEitherAsync(CompletionStage extends T> other, Consumer super T> action, Executor executor)
runAfterEither
: 执行俩任务,返回其中一个未出现异常的,并将该输出作为参数传入后续Runnable
(无参无返回值)
public CompletableFuture runAfterEither(CompletionStage> other, Runnable action)
public CompletableFuture runAfterEitherAsync(CompletionStage> other, Runnable action)
public CompletableFuture runAfterEitherAsync(CompletionStage> other, Runnable action, Executor executor)
2.2.3 执行两个任务全部完成
thenCombine
: 执行两个任务,并将这俩任务作为参数输入BiFunction
(有参有返回值)
public CompletableFuture thenCombine(CompletionStage extends U> other, BiFunction super T,? super U,? extends V> fn)
public CompletableFuture thenCombineAsync(CompletionStage extends U> other, BiFunction super T,? super U,? extends V> fn)
public CompletableFuture thenCombineAsync(CompletionStage extends U> other, BiFunction super T,? super U,? extends V> fn, Executor executor)
thenAcceptBoth
: 执行两个任务,并将这俩任务作为参数输入BiConsumer
(有参无返回值)
public CompletableFuture thenAcceptBoth(CompletionStage extends U> other, BiConsumer super T, ? super U> action)
public CompletableFuture thenAcceptBothAsync(CompletionStage extends U> other, BiConsumer super T, ? super U> action)
public CompletableFuture thenAcceptBothAsync(CompletionStage extends U> other, BiConsumer super T, ? super U> action, Executor executor)
runAfterBoth
: 执行两个任务,然后执行Runnable
(无参无返回值)
public CompletableFuture runAfterBoth(CompletionStage> other, Runnable action)
public CompletableFuture runAfterBothAsync(CompletionStage> other, Runnable action)
public CompletableFuture runAfterBothAsync(CompletionStage> other, Runnable action, Executor executor)
2.2.4 执行两个有依赖的任务
thenCompose
: 前一个任务的结果,要给第二个任务作为参数
public CompletableFuture thenCompose(Function super T, ? extends CompletionStage> fn)
public CompletableFuture thenComposeAsync(Function super T, ? extends CompletionStage> fn)
public CompletableFuture thenComposeAsync(Function super T, ? extends CompletionStage> fn, Executor executor)
2.2.5 组合更多的任务
allOf
: 等待所有任务都完成
public static CompletableFuture allOf(CompletableFuture>... cfs)
anyOf
: 等待完成任意一任务即可
public static CompletableFuture
2.3 结果获取
2.3.1 join
任务完成时获取数据,或者异常时抛出异常。不过要注意的是,它抛出的异常是(unchecked) exception
,CancellationException
或CompletionException
public T join()
2.3.2 get
在获取数据时: get()
等待任务完成然后读取结果; get(long timeout, TimeUnit unit)
有限时间内等待完成读取结果,或抛出TimeoutException
异常; getNow(T valueIfAbsent)
立即获取结果,或者缺省值;
public T get() throws InterruptedException, ExecutionException
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
public T getNow(T valueIfAbsent)
3 后记
今天主要熟悉了CompletableFuture
的绝大部分API,只有在合适的场景去使用才能融会贯通。后面会结合实际场景来讲讲如何使用它来做任务编排。
echo '5Y6f5Yib5paH56ugOiDmjpjph5Eo5L2g5oCO5LmI5Zad5aW26Iy25ZWKWzkyMzI0NTQ5NzU1NTA4MF0pL+aAneWQpihscGUyMzQp' | base64 -d