CompletableFuture 是 Java 8 引入的一个类,位于 java.util.concurrent 包中。它是 Future 接口的一个实现,但提供了更多的功能和灵活性来处理异步计算。相比于传统的 Future,CompletableFuture 允许以非阻塞的方式编排和组合异步任务,并且可以通过链式调用、异常处理等功能简化异步编程。
一、创建异步任务及获取
1.supplyAsync创建异步任务
supplyAsync会返回一个返回值,可以使用get方法去获取,返回值类型需要在泛型中指定。线程池如果不指定线程池则会使用默认线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
Executor executor);
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
使用:
//newFixedThreadPool是Java中一个常用的线程池类
ExecutorService executorService = Executors.newFixedThreadPool(10);
//supplyAsync有返回值,runAync没有返回值
CompletableFuture<String> task= CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName());
return Thread.currentThread().getName();
},executorService);
//获取返回值
System.out.println(task.get());
//使用完毕后要关闭线程池
executorService.shutdown();
2.runAsync创建异步任务
runAsync是一个无返回值的异步任务。
public static CompletableFuture<Void> runAsync(Runnable runnable,
Executor executor);
public static CompletableFuture<Void> runAsync(Runnable runnable);
使用:
ExecutorService executorService = Executors.newFixedThreadPool(10);
CompletableFuture<Void> task = CompletableFuture.runAsync(()->{
System.out.println(Thread.currentThread().getName());
},executorService);
executorService.shutdown();
3.配合supplyAsync,获取任务结果的方法
// 如果完成则返回结果,否则就抛出具体的异常
public T get() throws InterruptedException, ExecutionException
// 最大时间等待返回结果,否则就抛出具体异常
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
// 完成时返回结果值,否则抛出unchecked异常。为了更好地符合通用函数形式的使用,如果完成此 CompletableFuture所涉及的计算引发异常,则此方法将引发unchecked异常并将底层异常作为其原因
public T join()
// 如果完成则返回结果值(或抛出任何遇到的异常),否则返回给定的 valueIfAbsent。
public T getNow(T valueIfAbsent)
// 如果任务没有完成,返回的值设置为给定值
public boolean complete(T value)
// 如果任务没有完成,就抛出给定异常
public boolean completeExceptionally(Throwable ex)
二、任务编排处理
即调用主体taskA执行完后执行传参中的taskB。
thenApply和thenApplyAsync
任务类型:Function<T, R>
有入参,有返回值
thenAccept和thenAcceptAsync
任务类型:Consumer<T>
有入参,无返回值
thenRun和thenRunAsync
任务类型:
无入参,无返回值
1.thenApply和thenApplyAsync
thenApply 和 thenApplyAsync 都是 CompletableFuture 类中的方法,用于在前一个阶段完成时对结果进行衔接处理。然而,它们之间有一些关键的区别,主要体现在执行方式和线程使用上:
使用:
Supplier<U> 的U为返回值类型,而 Function<T, R> 的T为传参类型,R为返回值类型
//newFixedThreadPool是Java中一个常用的线程池类
ExecutorService executorService = Executors.newFixedThreadPool(10);
//创建任务内容
//Supplier<U> 是一个没有输入参数但能返回结果的函数式接口,而 Function<T, R> 则是一个接受一个输入参数并返回结果的接口。
Supplier<Integer> taskA= () ->{
Integer i = 1;
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
};
Function<Integer,String> taskB= s ->{
String i = s.toString()+1;
System.out.println(Thread.currentThread().getName()+"||"+i);
return i+"1";
};
//执行任务
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(taskA,executorService);
sleep(1);
//completableFuture.thenApply(taskB);
CompletableFuture<String> result= completableFuture.thenApplyAsync(taskB,executorService);
System.out.println("result:"+result.get());
executorService.shutdown();
2.thenAccept和thenAcceptAsync
thenAccept 和 thenAcceptAsync 都是 CompletableFuture 类中用于处理异步计算结果的方法,但它们在执行方式和线程使用上有所不同。这两个方法主要用于当你对前一个 CompletableFuture 的结果感兴趣,但不需要返回新的结果(即返回 void)时。
//newFixedThreadPool是Java中一个常用的线程池类
ExecutorService executorService = Executors.newFixedThreadPool(10);
//创建任务内容
//Supplier<U> 是一个没有输入参数但能返回结果的函数式接口,而 Consumer<T> 则是一个接受一个输入参数的接口。
Supplier<Integer> taskA= () ->{
Integer i = 1;
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
};
Consumer<Integer> taskB= s ->{
String i = s.toString()+1;
System.out.println(Thread.currentThread().getName()+"||"+i);
};
//执行任务
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(taskA,executorService);
sleep(1);
//completableFuture.thenAccept(taskB);
completableFuture.thenAcceptAsync(taskB,executorService);
executorService.shutdown();
3.thenRun和thenRunAsync
thenRun 和 thenRunAsync 是 CompletableFuture 类中提供的两种方法,用于在当前的 CompletableFuture 完成后执行一个Runnable任务。他们无需参数传入且无返回值:
//newFixedThreadPool是Java中一个常用的线程池类
ExecutorService executorService = Executors.newFixedThreadPool(10);
//创建任务内容
//Supplier<U> 是一个没有输入参数但能返回结果的函数式接口,而 Runnable则是无参无返回值的接口。
Supplier<Integer> taskA= () ->{
Integer i = 1;
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
};
Runnable taskB= () ->{
String i = "2";
System.out.println(Thread.currentThread().getName()+"||"+i);
};
//执行任务
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(taskA,executorService);
sleep(1);
//completableFuture.thenRun(taskB);
completableFuture.thenRunAsync(taskB,executorService);
executorService.shutdown();
4.then**和then**Async的不同点
then**
- 同步执行:当调用then**方法时,提供的函数会在当前的 CompletableFuture 完成时,在同一个线程中同步执行。
- 不指定执行器:由于它是同步执行的,因此不需要提供一个 Executor 来决定在哪一个线程中运行该函数。
then**Async
- 异步执行:与 then**不同,then**Async 提供的函数将在不同的线程中异步执行。这使得它可以避免阻塞主线程,特别是当操作可能需要一些时间完成时。
- 可指定执行器:你可以选择性地提供一个 Executor 来控制函数将在哪个线程池中执行。如果你没有提供执行器,则会使用 ForkJoinPool.commonPool() 作为默认的执行器。
三、多任务组合处理
1.thenCombine、thenAcceptBoth 和 runAfterBoth
thenCombine、thenAcceptBoth 和 runAfterBoth 是 CompletableFuture 类中用于组合两个 CompletableFuture 的方法。它们允许你以不同的方式处理两个异步操作的结果。如果有三个及以上,需要组合使用 thenCombine或thenAcceptBoth或runAfterBoth。
thenCombine
- 功能:当两个 CompletableFuture 都完成后,使用提供的 BiFunction 将它们的结果结合起来,并返回一个新的 CompletableFuture。
- 返回类型:返回一个新的 CompletableFuture<U>,其中 U 是 BiFunction 的结果类型。
- 适用场景:当你需要等待两个异步操作都完成,并且想要根据这两个操作的结果进行一些计算或创建新的结果时非常有用。
thenAcceptBoth
- 功能:当两个 CompletableFuture 都完成后,提供一个 BiConsumer 来处理它们的结果,但不返回任何结果(即返回 CompletableFuture<Void>)。
- 返回类型:返回一个 CompletableFuture<Void>,因为它不产生新的结果。
- 适用场景:当你需要等待两个异步操作都完成,并且想要基于这两个操作的结果执行某些操作(如日志记录、更新UI等),但不需要生成新的结果时非常有用。
runAfterBoth
- 功能:当两个 CompletableFuture 都完成后,运行一个 Runnable,不接收任何参数也不返回任何结果(即返回 CompletableFuture<Void>)。
- 返回类型:返回一个 CompletableFuture<Void>,因为它只是执行某个动作而不产生新的结果。
- 适用场景:当你需要在两个异步操作都完成后执行某些动作(如资源清理、发送通知等),但不需要使用这两个操作的结果时非常有用。
使用:
//newFixedThreadPool是Java中一个常用的线程池类
ExecutorService executorService = Executors.newFixedThreadPool(10);
CompletableFuture<Integer> taskA = CompletableFuture.supplyAsync(() ->{
Integer i = 1;
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
},executorService);
CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() ->{
String i = "2";
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
});
//thenAcceptBoth
taskA.thenAcceptBoth(taskB,(resultA,resultB)->{
System.out.println(resultA.toString()+resultB);
});
//runAfterBoth
taskA.runAfterBoth(taskB,()->{
System.out.println("All Complete!");
});
//thenCombine
CompletableFuture<String> result = taskA.thenCombine(taskB,(resultA,resultB)->{
return resultA.toString()+resultB;
});
System.out.println("result:"+result.get());
executorService.shutdown();
2.applyToEither、acceptEither和runAfterEither
applyToEither、acceptEither 和 runAfterEither 是 CompletableFuture 类中用于处理竞争条件的方法。它们允许你在多个 CompletableFuture 中任意一个完成时执行特定的操作,而不需要等待所有的 CompletableFuture 都完成。
applyToEither
- 功能:当提供的两个 CompletableFuture 中任意一个完成时,使用提供的 Function 对其结果进行转换,并返回一个新的 CompletableFuture。
- 返回类型:返回一个新的 CompletableFuture<U>,其中 U 是 Function 的结果类型。
- 适用场景:当你有多个异步操作,只需要其中一个的结果来生成新的结果时非常有用。
acceptEither
- 功能:当提供的两个 CompletableFuture 中任意一个完成时,提供一个 Consumer 来处理其结果,但不返回任何结果(即返回 CompletableFuture<Void>)。
- 返回类型:返回一个 CompletableFuture<Void>,因为它不产生新的结果。
- 适用场景:当你只需要处理两个 CompletableFuture 中任意一个的结果,而不需要生成新的结果时非常有用。
runAfterEither
- 功能:当提供的两个 CompletableFuture 中任意一个完成时,运行一个 Runnable,不接收任何参数也不返回任何结果(即返回 CompletableFuture<Void>)。
- 返回类型:返回一个 CompletableFuture<Void>,因为它只是执行某个动作而不产生新的结果。
- 适用场景:当你希望在两个 CompletableFuture 中任意一个完成后执行某些操作(如资源清理、发送通知等),但不需要使用这些操作的结果时非常有用。
使用:
//newFixedThreadPool是Java中一个常用的线程池类
ExecutorService executorService = Executors.newFixedThreadPool(10);
CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() ->{
String i = "1";
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
},executorService);
CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() ->{
String i = "2";
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
},executorService);
//acceptEither
taskA.acceptEither(taskB,(resultOne)->{
System.out.println("resultOne:"+resultOne);
});
//runAfterEither
taskA.runAfterEither(taskB,()->{
System.out.println("One Complete!");
});
//applyToEither
CompletableFuture<String> result = taskA.applyToEither(taskB,(resultOne)->{
return resultOne;
});
System.out.println("result:"+result.get());
executorService.shutdown();
四、针对多任务的异常处理
1.whenComplete和handle
whenComplete 和 handle 都是 CompletableFuture 类中用于处理任务完成后的回调操作的方法,对比上述编排方法,可以处理异常,whenComplete无返回值,handle会返回一个CompleteFuture<?>。
whenComplete使用:
CompletableFuture.supplyAsync(() -> {
return "Hello";
}).whenComplete((result, exception) -> {
if (exception != null) {
System.out.println("Exception occurred: " + exception.getMessage());
} else {
System.out.println("Result is: " + result);
}
});
handle使用:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟异常
throw new RuntimeException("Test Exception");
}).handle((result, exception) -> {
if (exception != null) {
System.out.println("Caught exception: " + exception.getMessage());
return "Default Value";
} else {
return result;
}
});
future.thenAccept(result -> System.out.println("Final Result: " + result));
五、阻塞进程等待异步处理
1.allOf和anyOf
CompletableFuture.allOf 和 CompletableFuture.anyOf 是 Java 中用于组合多个 CompletableFuture 的静态方法,它们提供了不同的方式来等待这些 CompletableFuture 的完成。可以处理异常。
CompletableFuture.allOf
- 功能:allOf 方法接收一个 CompletableFuture<?>... cfs 可变参数列表(即一个或多个 CompletableFuture),并返回一个新的 CompletableFuture<Void>,这个新的 CompletableFuture 会在所有提供的 CompletableFuture 都完成后才完成。
- 返回类型:返回的 CompletableFuture<Void> 不包含任何结果值。如果需要获取每个 CompletableFuture 的结果,你需要单独调用各自的 join() 或 get() 方法。
- 适用场景:当你需要等待一组异步任务全部完成后再进行后续处理时非常有用
使用:
//newFixedThreadPool是Java中一个常用的线程池类
ExecutorService executorService = Executors.newFixedThreadPool(10);
CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() ->{
String i = "1";
try {
sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
},executorService);
CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() ->{
String i = "2";
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
},executorService);
CompletableFuture<String> taskC = CompletableFuture.supplyAsync(() ->{
String i = "3";
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
},executorService);
//allOf
CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(taskA,taskB,taskC);
allOfFuture.get();
System.out.println("阻塞后执行语句");
executorService.shutdown();
CompletableFuture.anyOf
- 功能:anyOf 方法接收一个 CompletableFuture<?>... cfs 可变参数列表,并返回一个新的 CompletableFuture<Object>,这个新的 CompletableFuture 会在任意一个提供的 CompletableFuture 完成后就立即完成。
- 返回类型:返回的 CompletableFuture<Object> 包含第一个完成的 CompletableFuture 的结果。需要注意的是,由于Java泛型的原因,结果被声明为 Object 类型,因此你可能需要进行类型转换。
- 适用场景:当你有一组异步任务,并且只需要其中一个任务的结果时非常有用。例如,实现一种“竞态”机制,哪个任务先完成就使用哪个任务的结果。
使用:
//newFixedThreadPool是Java中一个常用的线程池类
ExecutorService executorService = Executors.newFixedThreadPool(10);
CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() ->{
String i = "1";
try {
sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
},executorService);
CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() ->{
String i = "2";
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
},executorService);
CompletableFuture<String> taskC = CompletableFuture.supplyAsync(() ->{
String i = "3";
try {
sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"||"+i);
return i;
},executorService);
//allOf
CompletableFuture<Object> allOfFuture = CompletableFuture.anyOf(taskA,taskB,taskC);
allOfFuture.get();
System.out.println("阻塞后执行语句");
executorService.shutdown();
2.runAfterBoth/runAfterEither和allOf/anyOf不同点
- runAfterBoth 和 runAfterEither 主要是为了在特定条件下(两个都完成或任一完成)执行一些副作用操作(如日志记录),并不直接提供任何结果。
- allOf 和 anyOf 则用于组合多个 CompletableFuture 并基于这些组合的状态(所有完成或任一完成)来决定下一步的动作,前者等待所有完成后者则在任意一个完成时即刻响应。
1090

被折叠的 条评论
为什么被折叠?



