文章目录
- 参考
- CompletableFuture引入
- 使用CompletableFuture作为Future实现
- 每一种方法都有三种形式
- 创建一个异步任务
- 计算完成时对结果的处理 whenComplete、exceptionally、handle
- 结果处理转换 thenApply
- 纯消费 thenAccept、thenRun、thenAcceptBoth、runAfterBoth
- 组合 thenCompose、thenCombine
- 任意一个方法执行完成就结束acceptEither、applyToEither
- 辅助方法allOf、anyOf
- 使用CompletableFuture提升程序性能
- CompletableFuture使用详解
参考
Java CompletableFuture 详解
CompletableFuture基本用法
使用了CompletableFuture之后,程序性能提升了三倍
Java8的CompletableFuture进阶之道–开发时看这个
CompletableFuture引入
Future是JDK5添加的类,用来描述一个异步计算的结果。可以使用isDone
方法检查计算是否完成,或者使用get
阻塞住调用线程,直到计算完成返回结果,也可以使用cancel
方法停止任务的执行。
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(10);
Future<Integer> f = executorService.submit(() ->{
// 长时间的异步计算
// 然后返回结果
System.out.println("A");
return 100;
});
// while(!f.isDone()){
// System.out.println("D");
// }
System.out.println("B");
Integer i = f.get();
System.out.println("C" + i);
executorService.shutdown();
return;
}
结果:
B
A
C100
虽然Future以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和异步编程的初衷相违背,轮询的方式又会耗费无谓的CPU资源,而且也不能及时地得到计算结果,所以可以用观察者设计模式,当计算结果完成及时通知监听者。
在JDK8里面,就新增了CompletableFuture类,提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了转换和组合CompletableFuture的方法。
CompletableFuture实现了Future、CompletionStage接口。CompletionStage接口定义了可与其他Future组合成异步计算契约。
使用CompletableFuture作为Future实现
CompletableFuture类实现Future接口,因此可以将其用作Future实现,但需要额外的完成实现逻辑。
例如:可以使用无构参构造函数创建此类的实例,然后使用complete方法完成。消费者可以使用get方法来阻塞当前线程,直到get()结果。
在下面的示例中,有一个创建CompletableFuture实例的方法,然后在另一个线程中计算并立即返回Future。
计算完成后,该方法通过将结果提供给完整方法来完成Future:
public static void main(String[] args) throws Exception{
Future<String> future = calculateAsync();
System.out.println(Thread.currentThread().getName() + " main");
System.out.println(future.get());
}
public static Future<String> calculateAsync() {
CompletableFuture<String> completableFuture = new CompletableFuture<>();
Executors.newCachedThreadPool().execute(() -> {
System.out.println(Thread.currentThread().getName() + " execute");
String result = "Hello " + " World";
completableFuture.complete(result);
});
return completableFuture;
}
结果:
main main
pool-1-thread-1 execute
Hello World
每一种方法都有三种形式
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)
- 非异步方法由当前线程或调用线程执行
- 不带executor的异步方法使用asyncPool来执行
1)如果不支持多线程,则新建一个线程专门执行
2)否则使用ForkJoinPool.commonPool()
执行 - 另一种异步方法使用executor执行
创建一个异步任务
CompletableFuture.completedFuture
是一个静态辅助方法,用来返回一个已经计算好的CompletableFuture
。
public static <U> CompletableFuture<U> completedFuture(U value)
Async结尾的方法都是可以异步执行的,如果指定了线程池,会在指定的线程池中执行,如果没有指定,默认会在ForkJoinPool.commonPool()
中执行。
- runAsync方法:它以
Runnabel
函数式接口类型为参数,所以CompletableFuture的计算结果为空。 - supplyAsync方法:以
Supplier<U>
函数式接口类型为参数,所以CompletableFuture有返回值,且计算结果类型为U。
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> System.out.println("runAsync"));
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "supplyAsync");
System.out.println(future1.get());
System.out.println(future2.get());
结果:
runAsync
null
supplyAsync
计算完成时对结果的处理 whenComplete、exceptionally、handle
当CompletableFuture的计算结果完成,或者抛出异常的时候,我们可以执行特定的Action。
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
参数类型为 BiConsumer<? super T, ? super Throwable>
会获取上一步计算的计算结果和异常信息。
以Async结尾的方法可能会使用其它的线程去执行,如果使用相同的线程池,也可能会被同一个线程选中执行。
public class ThreadUtil {
public static void sleep(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
}
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
ThreadUtil.sleep(100);
return 20;
}).whenCompleteAsync((v, e) -> {
System.out.println("VV:" + v);
System.out.println("EE:" + e);
});
System.out.println("A");
System.out.println(future.get());
System.out.println("B");
结果:
A
VV:20
EE:null
20
B
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
该方法是对异常情况的处理,当函数异常时执行。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
ThreadUtil.sleep(100);
return 20/0;
}).whenCompleteAsync((v, e) -> {
System.out.println("VV:" + v);
System.out.println("EE:" + e);
}).exceptionally((e)->{
System.out.println(e.getMessage());
return 30;
});
System.out.println("A");
System.out.println(future.get());
System.out.println("B");
结果:
A
VV:null
EE:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
java.lang.ArithmeticException: / by zero
30
B
public <U> CompletableFuture<U> handle(BiFunction<? super T,Throwable,? extends U> fn)
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn)
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn, Executor executor)
handle 方法和whenComplete方法类似,只不过接收的是一个 BiFunction<? super T,Throwable,? extends U> fn
类型的参数,因此有 whenComplete
方法和 转换的功能 (thenApply
)。
以Async结尾的方法可能会使用其它的线程去执行,如果使用相同的线程池,也可能会被同一个线程选中执行。
CompletableFuture<Integer> future = CompletableFuture
.supplyAsync(() -> {
ThreadUtil.sleep(100);
return 20;
})
.handle((t, e)->{
System.out.println("TT:" + t);
System.out.println("EE:" + e);
return 10;
});
System.out.println("A");
System.out.println(future.get());
System.out.println("B");
结果:
A
TT:20
EE:null
10
B
// 异常情况
CompletableFuture<Integer> future = CompletableFuture
.supplyAsync(() -> {
ThreadUtil.sleep(100);
return 20/0;
})
.handle((t, e)->{
System.out.println("TT:" + t);
System.out.println("EE:" + e);
return 10;
});
System.out.println("A");
System.out.println(future.get());
System.out.println("B");
结果:
A
TT:null
EE:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
10
B
结果处理转换 thenApply
当前阶段正常完成以后执行,而且当前阶段的执行的结果会作为下一阶段的输入参数。
thenApplyAsync默认是异步执行的。这里所谓的异步指的是不在当前线程内执行。
thenApply相当于回调函数(callback)。
CompletableFuture 由于有回调,可以不必等待一个计算完成而阻塞着调用线程,可以在一个结果计算完成之后紧接着执行某个Action。我们可以将这些操作串联起来。
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)
CompletableFuture<Integer> future = CompletableFuture
.supplyAsync(() -> {
ThreadUtil.sleep(100);
return 20;
})
.thenApply((f1)->{
System.out.println("F1:" + f1);
return f1 * 2;
})
.thenApply((f2)->{
System.out.println("F2:" + f2);
return f2 * 2;
})
.thenApply((f3)->{
System.out.println("F3:" + f3);
return f3 * 2;
});
System.out.println("A");
System.out.println("future:" + future.get());
System.out.println("B");
结果:
A
F1:20
F2:40
F3:80
future:160
B
这些方法不是马上执行的,也不会阻塞,而是前一个执行完成后继续执行下一个。
和 handle 方法的区别是,handle 会处理正常计算值和异常,不会抛出异常。而 thenApply 只会处理正常计算值,有异常则抛出。
纯消费 thenAccept、thenRun、thenAcceptBoth、runAfterBoth
thenAccept和thenRun都是无返回值的。如果说thenApply是不停的输入输出的进行生产,那么thenAccept和thenRun就是在进行消耗。它们是整个计算的最后两个阶段。
- thenAccept接收上一阶段的输出作为本阶段的输入
- thenRun根本不关心前一阶段的输出,根本不不关心前一阶段的计算结果,因为它不需要输入参数
单纯的去消费结果而不会返回新的值,因些计算结果为 Void。
public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
ThreadUtil.sleep(100);
return 20;
}).thenAccept((c)->{
System.out.println("CC:" + c);
}).thenAcceptAsync((c2)->{
System.out.println("C2:" + c2);
});
System.out.println("A");
System.out.println(future.get());
System.out.println("B");
结果:
A
CC:20
C2:null
null
B
public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T,? super U> action)
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T,? super U> action)
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T,? super U> action, Executor executor)
和 thenAccept 相比,参数类型多了一个CompletionStage<? extends U> other
,BiConsumer第一个参数接收第一个supplyAsync返回值,第二个参数接收CompletionStage返回值。
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
ThreadUtil.sleep(100);
return 20;
}).thenAcceptBoth(CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return 2;
}), (a, b)->{
System.out.println(Thread.currentThread().getName() + "-AA:" + a);
System.out.println(Thread.currentThread().getName() + "-BB:" + b);
});
System.out.println("A");
System.out.println(future.get());
System.out.println("B");
结果:
ForkJoinPool.commonPool-worker-1
ForkJoinPool.commonPool-worker-2
A
ForkJoinPool.commonPool-worker-1-AA:20
ForkJoinPool.commonPool-worker-1-BB:2
null
B
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other, Runnable action)
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action)
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action, Executor executor)
runAfterBoth 和以上方法不同,传一个 Runnable 类型的参数,不接收上一级的返回值
更彻底的:public CompletableFuture<Void> thenRun(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action, Executor executor)
以上是彻底的纯消费,完全忽略计算结果。
组合 thenCompose、thenCombine
public <U> CompletableFuture<U> thenCompose(Function<? super T,? extends CompletionStage<U>> fn)
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T,? extends CompletionStage<U>> fn)
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T,? extends CompletionStage<U>> fn, Executor executor)
以上接收类型为 Function<? super T,? extends CompletionStage<U>> fn
,fn 接收上一级返回的结果,并返回一个新的 CompletableFuture。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " A");
ThreadUtil.sleep(100);
return 20;
}).thenApply((f)->{
System.out.println(Thread.currentThread().getName() + " B");
return f + 10;
}).thenCompose((s)->{
System.out.println(Thread.currentThread().getName() + " SS:" + s);
return CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " C");
return s * 5;
});
});
System.out.println("A");
System.out.println(future.get());
System.out.println("B");
结果:
ForkJoinPool.commonPool-worker-1 A
A
ForkJoinPool.commonPool-worker-1 B
ForkJoinPool.commonPool-worker-1 SS:30
ForkJoinPool.commonPool-worker-2 C
150
B
public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn, Executor executor)
两个CompletionStage是并行执行的,它们之间并没有先后依赖顺序,other并不会等待先前的CompletableFuture执行完毕后再执行。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
ThreadUtil.sleep(1000);
System.out.println(Thread.currentThread().getName());
return 20;
}).thenApply((f)->{
ThreadUtil.sleep(1000);
System.out.println(Thread.currentThread().getName());
return f + 10;
}).thenCombine(CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " thenCombineAsync");
return 10;
}), (x, y)->{
System.out.println(Thread.currentThread().getName() + " XX:" + x);
System.out.println(Thread.currentThread().getName() + " YY:" + y);
return x + y;
});
System.out.println("A");
System.out.println(future.get());
System.out.println("B");
结果:
ForkJoinPool.commonPool-worker-2 thenCombineAsync
A
ForkJoinPool.commonPool-worker-1
ForkJoinPool.commonPool-worker-1
ForkJoinPool.commonPool-worker-1 XX:30
ForkJoinPool.commonPool-worker-1 YY:10
40
B
thenCombine
和 supplyAsync
不一定哪个先哪个后,是并行执行的。
任意一个方法执行完成就结束acceptEither、applyToEither
public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action)
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor)
Random random = new Random();
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
ThreadUtil.sleep(random.nextInt(1000));
return "A";
}).acceptEither(CompletableFuture.supplyAsync(() -> {
ThreadUtil.sleep(random.nextInt(1000));
return "B";
}), (c) -> {
System.out.println(c);
});
System.out.println(future.get());
结果:
B
null
或者:
A
null
以上代码有时输出A,有时输出B,哪个Future先执行完就会根据它的结果计算。
acceptEither方法是当任意一个 CompletionStage 完成的时候,action 这个消费者就会被执行。这个方法返回 CompletableFuture<Void>
。
public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T,U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T,U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T,U> fn, Executor executor)
applyToEither 方法是当任意一个 CompletionStage 完成的时候,fn会被执行,它的返回值会当作新的CompletableFuture<U>
的计算结果。
Random random = new Random();
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
ThreadUtil.sleep(random.nextInt(1000));
return "A";
}).applyToEither(CompletableFuture.supplyAsync(() -> {
ThreadUtil.sleep(random.nextInt(1000));
return "B";
}), (c) -> {
System.out.println(c);
return c + "DD";
});
System.out.println(future.get());
结果:
B
BDD
或者:
A
ADD
acceptEither 和 applyToEither 区别是: acceptEither 没有返回值,applyToEither 有返回值。
辅助方法allOf、anyOf
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
当所有的CompletableFuture都执行完后才往下执行,没有返回值。public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
当任意一个CompletableFuture执行完后就会执行计算,计算的结果相同,返回一个Object类型的值。
使用CompletableFuture提升程序性能
如果每个操作都很简单的话,没有必要用这种多线程异步的方式,因为创建线程还需要时间,还不如直接同步执行来得快。
只有当每个操作很复杂需要花费相对很长的时间(比如,调用多个其它的系统的接口;比如,商品详情页面这种需要从多个系统中查数据显示的)的时候用CompletableFuture才合适,不然区别真的不大,还不如顺序同步执行。
定义一个对象:
@Data
public class UserInfo {
private Integer id;
private String name;
private Integer jobId;
private String jobDes;
private Integer carId;
private String carDes;
private Integer homeId;
private String homeDes;
}
这个对象里面的homeid,jobid,carid都是用于匹配对应的住房信息描述,职业信息描述,购车信息描述。
对于将id转换为描述信息的方式需要通过额外的sql查询,这里做了个简单的工具类来进行模拟:
import java.util.concurrent.TimeUnit;
public class QueryUtils {
public String queryCar(Integer carId){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "car_desc";
}
public String queryJob(Integer jobId){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "job_desc";
}
public String queryHome(Integer homeId){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "home_desc";
}
}
假设每次查询需要消耗1s,那么遍历的一个size为n的集合查询消耗的时间就是n * 3s。
下面来使用CompletableFuture提升性能:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class QueryUserService {
private Supplier<QueryUtils> queryUtilsSupplier = new Supplier<QueryUtils>() {
@Override
public QueryUtils get() {
return new QueryUtils();
}
};
// 传统方式
public UserInfo converUserInfo(UserInfo userInfo) {
userInfo.setCarDes(queryUtilsSupplier.get().queryCar(userInfo.getCarId()));
userInfo.setHomeDes(queryUtilsSupplier.get().queryHome(userInfo.getHomeId()));
userInfo.setJobDes(queryUtilsSupplier.get().queryJob(userInfo.getJobId()));
return userInfo;
}
// CompletableFuture方式
public UserInfo converUserInfoForFuture(UserInfo userInfo) {
CompletableFuture<String> getCarDesc = CompletableFuture.supplyAsync(() -> queryUtilsSupplier.get().queryCar(userInfo.getCarId()));
getCarDesc.thenAccept((carDesc) -> userInfo.setCarDes(carDesc));
CompletableFuture<String> getHomeDesc = CompletableFuture.supplyAsync(() -> queryUtilsSupplier.get().queryHome(userInfo.getHomeId()));
getHomeDesc.thenAccept((homeDesc) -> userInfo.setHomeDes(homeDesc));
CompletableFuture<String> getJobDesc = CompletableFuture.supplyAsync(() -> queryUtilsSupplier.get().queryJob(userInfo.getJobId()));
getJobDesc.thenAccept((jobDesc) -> userInfo.setJobDes(jobDesc));
CompletableFuture<Void> getUserInfo = CompletableFuture.allOf(getCarDesc, getHomeDesc, getJobDesc);
getUserInfo.thenAccept(new Consumer<Void>() {
@Override
public void accept(Void result) {
System.out.println("全部完成查询");
}
});
getUserInfo.join();
return userInfo;
}
public static void main(String[] args) {
long begin = System.currentTimeMillis();
// 多线程环境需要注意线程安全问题
List<UserInfo> userInfoList = Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i <= 20; i++) {
UserInfo userInfo = new UserInfo();
userInfo.setId(i);
userInfo.setName("username" + i);
userInfo.setCarId(i);
userInfo.setJobId(i);
userInfo.setHomeId(i);
userInfoList.add(userInfo);
}
QueryUserService queryUserService = new QueryUserService();
//stream 查询一个用户花费3s 并行计算后一个用户1秒左右 查询21个用户花费21秒
userInfoList.stream().map(userInfo -> {
userInfo = queryUserService.converUserInfoForFuture(userInfo);
return userInfo;
}).collect(Collectors.toList());
System.out.println("=============");
long end = System.currentTimeMillis();
System.out.println(end - begin);
}
}
CompletableFuture使用详解
static方法说明
CompletableFuture的几个 static 方法,它们可以实例化一个 CompletableFuture 实例。
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
runAsync
方法接收的是Runnable
的实例,但是它没有返回值。supplyAsync
方法是JDK8函数式接口,无参数,会返回一个结果。- 这两个方法是
executor
的升级,表示让任务在指定的线程池中执行,不指定的话,通常任务是在ForkJoinPool.commonPool()
线程池中执行的。
supplyAsync()使用
静态方法runAsync
和supplyAsync
允许我们相应地从Runnable
和Supplier
功能类型中创建CompletableFuture
实例。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " A");
return "Hello";
});
System.out.println(Thread.currentThread().getName() + " B");
System.out.println(future.get());
结果:
main B
ForkJoinPool.commonPool-worker-1 A
Hello
thenRun()使用
在两个任务任务A,任务B中,如果既不需要任务A的值也不想在任务B中引用,那么你可以将Runnable lambda 传递给thenRun()方法。
在下面的示例中,在调用future.get()方法之后,我们只需在控制台中打印一行:
模板
CompletableFuture.runAsync(() -> {}).thenRun(() -> {});
CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {});
- 第一行用的是
thenRun(Runnable runnable)
,任务 A 执行完执行 B,并且 B 不需要 A 的结果。 - 第二行用的是
supplyAsync(Supplier<U> supplier)
,任务 A 执行完执行 B,会返回resultA,但是 B 不需要 A 的结果。
实战
CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " A");
return "Hello";
}).thenRun(() -> {
System.out.println(Thread.currentThread().getName() + " Computation finished.");
});
System.out.println(Thread.currentThread().getName() + " B");
System.out.println(completableFuture.get());
结果:
ForkJoinPool.commonPool-worker-1 A
main Computation finished.
main B
null
thenAccept()使用
在两个任务任务A,任务B中,如果你不需要在Future中有返回值,则可以用 thenAccept方法接收将计算结果传递给它。最后的future.get()调用返回Void类型的实例。
模板
CompletableFuture.runAsync(() -> {}).thenAccept(resultA -> {});
CompletableFuture.supplyAsync(() -> "resultA").thenAccept(resultA -> {});
- 第一行中,runAsync不会有返回值,第二个方法thenAccept,接收到的resultA值为null,同时任务B也不会有返回结果。
- 第二行中,supplyAsync有返回值,同时任务B不会有返回结果。
实战
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " A");
return "Hello";
});
CompletableFuture<Void> future = completableFuture.thenAccept(s -> {
System.out.println(Thread.currentThread().getName() + " Computation returned: " + s);
});
System.out.println(Thread.currentThread().getName() + " B");
System.out.println(future.get());
结果:
ForkJoinPool.commonPool-worker-1 A
main Computation returned: Hello
main B
null
来源:CSDN
作者:const_
链接:https://blog.csdn.net/const_/article/details/104576827