一:创建任务并执行任务
1:无参创建:CompletableFuture<String> noArgsFuture = new CompletableFuture<>();
2:传入相应任务,无返回值(runAsync
方法可以在后台执行异步计算,但是此时并没有返回值。持有一个Runnable
对象。)
CompletableFuture noReturn = CompletableFuture.runAsync(()->{
//执行逻辑,无返回值
});
3:传入相应任务,有返回值;(此时我们看到返回的是CompletableFuture<T>
此处的T
就是你想要的返回值的类型。其中的Supplier<T>
是一个简单的函数式接口。)
CompletableFuture<String> hasReturn = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
return "hasReturn";
}
});
此时可以使用lambda
表达式使上面的逻辑更加清晰:get方法获取返回结果
CompletableFuture<String> hasReturnLambda = CompletableFuture.supplyAsync(TestFuture::get);
3:获取返回值(异步任务也是有返回值的,当我们想要用到异步任务的返回值时,我们可以调用CompletableFuture
的get()
阻塞,直到有异步任务执行完有返回值才往下执行)
4:自定义返回值(我们也可以在任意时候调用complete()
方法来自定义返回值)
CompletableFuture<String> future1 = new CompletableFuture<>();
System.out.println("main method is invoking");
try {
new Thread(()->{
System.out.println("thread is invoking");
try {
Thread.sleep(5000);
future1.complete("123456");
}catch (Exception e){
e.printStackTrace();
}
System.out.println("thread is end");
}).run();
System.out.println("Main Method End value is " + future1.get());
}catch (Exception e){
e.printStackTrace();
}
二:按顺序执行异步任务
如果有一个异步任务的完成需要依赖前一个异步任务的完成,那么该如何写呢?是调用get()
方法获得返回值以后然后再执行吗?这样写有些麻烦,CompletableFuture
为我们提供了方法来完成我们想要顺序执行一些异步任务的需求。thenApply
、thenAccept
、thenRun
这三个方法。这三个方法的区别就是。
一般来说thenAccept
、thenRun
这两个方法在调用链的最末端使用。实例如下:
// thenApply 可获取前一个任务的返回值,自身也有返回值
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "one");
CompletableFuture<String> future2 = future1.thenApply(name -> name + "two");
try{
System.out.println(future2.get());
}catch (Exception e){
e.printStackTrace();
}
// thenAccept 可获取前一个任务的返回值,但是自身没有返回值
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "three");
future3.thenAccept(name -> System.out.println(name + "thenAccept"));
System.out.println("----------------------");
try{
System.out.println(future3.get());
}catch (Exception e){
e.printStackTrace();
}
//thenRun 获取不到前一个任务的返回值,也无返回值
System.out.println("-------------");
CompletableFuture<Void> thenRun = future3.thenRun(() -> {
System.out.println("thenRun");
});
try{
System.out.println(thenRun.get());
}catch (Exception e){
e.printStackTrace();
}
1:thenApply和thenApplyAsync的区别
如果使用thenApplyAsync
,那么执行的线程是从ForkJoinPool.commonPool()
中获取不同的线程进行执行,如果使用thenApply
,如果supplyAsync
方法执行速度特别快,那么thenApply
任务就是主线程进行执行,如果执行特别慢的话就是和supplyAsync
执行线程一样。接下来我们通过例子来看一下,使用sleep
方法来反应supplyAsync
执行速度的快慢。
//thenApply和thenApplyAsync的区别
System.out.println("-------------");
CompletableFuture<String> supplyAsyncWithSleep = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "supplyAsyncWithSleep Thread Id : " + Thread.currentThread();
});
CompletableFuture<String> thenApply = supplyAsyncWithSleep
.thenApply(name -> name + "------thenApply Thread Id : " + Thread.currentThread());
CompletableFuture<String> thenApplyAsync = supplyAsyncWithSleep
.thenApplyAsync(name -> name + "------thenApplyAsync Thread Id : " + Thread.currentThread());
System.out.println("Main Thread Id: "+ Thread.currentThread());
System.out.println(thenApply.get());
System.out.println(thenApplyAsync.get());
System.out.println("-------------No Sleep");
CompletableFuture<String> supplyAsyncNoSleep = CompletableFuture.supplyAsync(()->{
return "supplyAsyncNoSleep Thread Id : " + Thread.currentThread();
});
CompletableFuture<String> thenApplyNoSleep = supplyAsyncNoSleep
.thenApply(name -> name + "------thenApply Thread Id : " + Thread.currentThread());
CompletableFuture<String> thenApplyAsyncNoSleep = supplyAsyncNoSleep
.thenApplyAsync(name -> name + "------thenApplyAsync Thread Id : " + Thread.currentThread());
System.out.println("Main Thread Id: "+ Thread.currentThread());
System.out.println(thenApplyNoSleep.get());
System.out.println(thenApplyAsyncNoSleep.get());
三:组合CompletableFuture
将两个CompletableFuture组合在一起有两个方法:
thenCompose()
:当第一个任务完成时才会执行第二个操作thenCombine()
:两个异步任务全部完成时才会执行某些操作
thenCompose() 用法:
定义两个异步任务,假设第二个定时任务需要用到第一个定时任务的返回值。
public static CompletableFuture<String> getTastOne(){
return CompletableFuture.supplyAsync(()-> "topOne");
}
public static CompletableFuture<String> getTastTwo(String s){
return CompletableFuture.supplyAsync(()-> s + " topTwo");
}
利用thenCompose()
方法进行编写
CompletableFuture<String> thenComposeComplet = getTastOne().thenCompose(s -> getTastTwo(s));
System.out.println(thenComposeComplet.get());
// 输出: topOne topTwo
thenCombine() 用法:
例如我们此时需要计算两个异步方法返回值的和。求和这个操作是必须是两个异步方法得出来值的情况下才能进行计算,因此我们可以用thenCombine()
方法进行计算。
CompletableFuture<Integer> thenComposeOne = CompletableFuture.supplyAsync(() -> 192);
CompletableFuture<Integer> thenComposeTwo = CompletableFuture.supplyAsync(() -> 196);
CompletableFuture<Integer> thenComposeCount = thenComposeOne
.thenCombine(thenComposeTwo, (s, y) -> s + y);
System.out.println(thenComposeCount.get());
此时thenComposeOne
和thenComposeTwo
都完成时才会调用传给thenCombine
方法的回调函数。