[加精]漫画API | CompletableFuture


在我的开发工作中,有时候会遇到程序运行较慢导致用户在使用产品时请求反应时间较长,从而影响产品的用户体验,因此,我会考虑将一些顺序运行的程序改为异步运行,从而减少程序运行时间。


本文将了解的API是:

java.util.concurrent.CompletableFuture

CompletableFutureJDK1.8新加入的内容,实现了Future<T>CompletionStage<T>两个接口,可以用来构建异步应用,从而减少程序运行时间。

漫画API | CompletableFuture

漫画API | CompletableFuture

代码示例:

1
2
3
4
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
  // 程序体
  return "返回值内容";
});

API:

漫画API | CompletableFuture

解释说明:supplyAsyncrunAsync的区别在于是否包含了程序执行返回结果,可以看出supplyAsync返回结果是CompletableFuture<U>,而runAsync的返回结果是CompletableFuture<Void>

漫画API | CompletableFuture

代码示例:

1
2
3
4
5
CompletableFuture<String> f01 = CompletableFuture.supplyAsync(() -> {
  codeBody("f01"); // 程序体
  return "f01 success";
});
System.out.println(f01.join());

API:

漫画API | CompletableFuture

漫画API | CompletableFuture

代码示例:

1
2
3
4
5
6
7
8
9
CompletableFuture<String> fu1 = CompletableFuture.supplyAsync(() -> {
  codeBody("fu1"); // 程序体
  return "fu1 success";
});
CompletableFuture<Void> fu2 = CompletableFuture.runAsync(() -> {
  codeBody("fu2"); // 程序体
});
CompletableFuture.allOf(fu1, fu2).join();
CompletableFuture.anyOf(fu1, fu2).join();

API:

漫画API | CompletableFuture

重要提醒:

漫画API | CompletableFuture

漫画API | CompletableFuture

代码示例:

1
2
3
4
5
6
String result1 = CompletableFuture.supplyAsync(() -> {
  codeBody("async-1"); // 程序体
  return "async-1 success";
}).whenComplete((result, ex) -> {
  System.out.println(result);
}).join();

API:

漫画API | CompletableFuture

除了whenComplete之外,还有以下一些方法是继续执行的处理方法

漫画API | CompletableFuture

1thenApplythenAccept区别在于是否含有程序执行结果值

2thenApplythenAccept相同点在于均要求程序正常执行完成

漫画API | CompletableFuture

API:

漫画API | CompletableFuture

漫画API | CompletableFuture

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
  codeBody("f1"); // 程序体
  return "F1 ";
});
 
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
  codeBody("f2"); // 程序体
  return "F2 ";
}).applyToEither(f1, t -> { // t 是f1的执行结果
  System.out.println(t + "successfuly!");
  return "";
});

漫画API | CompletableFuture

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
  codeBody("f1"); // 程序体
  return "F1 ";
});
 
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
  codeBody("f2"); // 程序体
  return "F2 ";
}).applyToEither(f1, t -> { // t 是f1的执行结果
  System.out.println(t + "successfuly!");
  return "";
});
 
CompletableFuture<Void> f3 = CompletableFuture.supplyAsync(() -> {
  codeBody("f3-1"); // 程序体
  codeBody("f3-2"); // 程序体
  return "F3 ";
}).runAfterEither(f1, () -> { // runAfterEither不关心f1的执行结果
  System.out.println("successfuly!");
});

API:

漫画API | CompletableFuture

结语

很多相似方法的区别都在于后面加上了Async或是在参数中加入了Executor executor,如thenApply

1
2
3
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)

我个人觉得他们的理解用途是一致的,区别在于是否创建线程去执行任务,Async表示是否创建线程去异步执行,当未指定Executor时,默认采用ForkJoinPool.commonPool()作为线程池执行异步代码

 

从我个人使用的角度来看,我会把API的大部分方法通俗的分为几个大类

 

1、创建线程执行异步操作,如supplyAsync

2、单独获取程序执行结果的,如join

3、等待并确保异步操作是否完成的,如allof

4、异步操作和下一个异步操作加入关联的 ,如thenApply

5、两个同时异步操作存在关联的,如thenCombine

6、比较哪个更快的,如applyToEither

 

— END —

注:以上部分内容是阿木自己学习时总结出来的,如有不对的地方欢迎指出,非常感谢

原文始发于微信公众号(程序员阿木):漫画API | CompletableFuture