CompletableFuture的使用是为了异步编程,异步编程可以解决同步编程的性能瓶颈问题。也就是将同步操作变为了并行操作。
当我们有一大批数据需要处理的时候我们可以将这些数据分而治之,使用CompletableFuture通过线程池的多个线程进行异步执行。
public static CompletableFuture runAsync(Runnable runnable)
public static CompletableFuture runAsync(Runnable runnable, Executor executor)
public static CompletableFuture supplyAsync(Supplier supplier)
public static CompletableFuture supplyAsync(Supplier supplier, Executor executor)
/**
* @author yuanxindong
* @date 2020/7/30 9:07 下午
*/
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//
System.out.println(runAsyncDemo().get());
System.out.println(supplyAsyncDemo().get());
}
static CompletableFuture runAsyncDemo() {
CompletableFuture voidCompletableFuture = CompletableFuture.runAsync(CompletableFutureDemo::getMessage);
return voidCompletableFuture;
}
static CompletableFuture supplyAsyncDemo() {
CompletableFuture stringCompletableFuture1 =
CompletableFuture.supplyAsync(CompletableFutureDemo::getMessage);
return stringCompletableFuture1;
}
static String getMessage() {
return "return message";
}
}
执行结果:
null
return message
Process finished with exit code 0
当我们异步调用完成调用后,计算结果完成或者异常的时候我们应该如何接受结果呢?
下面有四种接受的方法
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)
public CompletableFuture exceptionally(Function fn)
不难看出形参名称为action的为正常回调的接受,形参为fn的为异常回调的接受。
whenComplete 和 whenCompleteAsync 的区别:
whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。
package 并发编程;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Function;
/**
* @author yuanxindong
* @date 2020/7/30 10:22 下午
*/
public class WhenCompleteDemo {
public static void main(String[] args) throws InterruptedException {
// 启动异步编程的一个线程任务
CompletableFuture future =
CompletableFuture.runAsync(
() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
if (new Random().nextInt() % 2 >= 0) {
int i = 12 / 0;
}
System.out.println("run end ...");
});
// 接受正常任务结果
future.whenComplete(
new BiConsumer() {
@Override
public void accept(Void t, Throwable action) {
System.out.println("执行完成!");
}
});
// 接受异常任务结果
future.exceptionally(
new Function() {
@Override
public Void apply(Throwable t) {
System.out.println("执行失败!" + t.getMessage());
return null;
}
});
TimeUnit.SECONDS.sleep(2);
}
private static void print(String message) {
System.out.println(message);
}
}
执行结果:
执行失败!java.lang.ArithmeticException: / by zero
执行完成!
Process finished with exit code 0
我们可以想一下应用场景,在我们下了订单之后我们给用户返回抽奖的场景。
下一个任务依赖上一个任务的结果
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)
Function super T,? extends U>
private static void thenApply() throws Exception {
CompletableFuture future = CompletableFuture.supplyAsync(new Supplier() {
@Override
public Long get() {
long result = new Random().nextInt(100);
System.out.println("result1="+result);
return result;
}
}).thenApply(new Function() {
@Override
public Long apply(Long t) {
long result = t*5;
System.out.println("result2="+result);
return result;
}
});
long result = future.get();
System.out.println(result);
}
执行结果
result1=46
result2=230
230
应用场景当我们进行调用第三方的接口的的时候,然后需要拿到结果进行处理。
handle 是执行任务完成时对结果的处理。
handle 方法和 thenApply 方法处理方式基本一样。不同的是 handle 是在任务完成后再执行,还可以处理异常的任务。thenApply 只可以执行正常的任务,任务出现异常则不执行 thenApply 方法(当异常被捕获后仍然可以执行)。
public CompletionStage handle(BiFunction super T, Throwable, ? extends U> fn);
public CompletionStage handleAsync(BiFunction super T, Throwable, ? extends U> fn);
public CompletionStage handleAsync(BiFunction super T, Throwable, ? extends U> fn,Executor executor);
public static void handle() throws Exception{
CompletableFuture future = CompletableFuture.supplyAsync(new Supplier() {
@Override
public Integer get() {
int i= 10/0;
return new Random().nextInt(10);
}
}).handle(new BiFunction() {
@Override
public Integer apply(Integer param, Throwable throwable) {
int result = -1;
if(throwable==null){
result = param * 2;
}else{
System.out.println(throwable.getMessage());
}
return result;
}
});
System.out.println(future.get());
}
从示例中可以看出,在 handle 中可以根据任务是否有异常来进行做相应的后续处理操作。而 thenApply 方法,如果上个任务出现错误,则不会执行 thenApply 方法。