CompletableFuture的acceptEither方法返回一个新的CompletionStage,当此两个任务中的任何一个正常完成时,将使用相应的结果作为所提供操作的参数来执行定义的Action,执行的Action没有返回值。
我们先来看一个demo,两个输出任务,哪个先完成,就输出哪个任务的结果
/**
* 使用CompletableFuture异步编程 消费计算结果
* @author www.itzhimei.com
*/
public class FutureTest_8 {
public static void main(String[] args) {
//执行10次两个输出任务
for(int i=0; i<10; i++) {
CompletableFuture.supplyAsync(()->"Test Task 1")
.acceptEither(CompletableFuture.supplyAsync(()->"Test Task 2"), System.out::println);
}
/* 输出
Test Task 1
Test Task 2
Test Task 1
Test Task 1
Test Task 1
Test Task 1
Test Task 1
Test Task 1
Test Task 1
Test Task 1
*/
}
}
从结果来看任务1输出了9次,任务2输出了1次,因为从程序的执行顺序上,任务1确实是先执行的,是比较有优势的,当然我们可以对代码做一些小小的改动来检查acceptEither方法是不是二选一,先返回的先执行。
import java.util.concurrent.CompletableFuture;
/**
* 使用CompletableFuture异步编程 消费计算结果
* @author www.itzhimei.com
*/
public class FutureTest_8 {
public static void main(String[] args) throws Exception {
//执行10次两个输出任务
for(int i=0; i<10; i++) {
CompletableFuture.supplyAsync(()->"Test Task 1")
.acceptEither(CompletableFuture.supplyAsync(()->"Test Task 2"), System.out::println).join();
}
/* 输出
Test Task 1
Test Task 2
Test Task 1
Test Task 1
Test Task 1
Test Task 1
Test Task 1
Test Task 1
Test Task 1
Test Task 1
*/
System.out.println("==================================================");
//执行10次两个输出任务
for(int i=0; i<10; i++) {
CompletableFuture.supplyAsync(()->FutureTest_8.getTaskResult(1000, "Test Task 1"))
.acceptEither(CompletableFuture.supplyAsync(()->FutureTest_8.getTaskResult(500, "Test Task 2")), System.out::println).join();
}
/* 输出
Test Task 2
Test Task 2
Test Task 2
Test Task 2
Test Task 2
Test Task 2
Test Task 2
Test Task 2
Test Task 2
Test Task 2
*/
}
public static String getTaskResult(long sleepTime, String task) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
return task;
}
}
我们改造后的代码,加入了计算延时,第一个任务是1秒延时,第二个任务是0.5秒延时,所以程序每次都是用了任务2的结果进行输出。
CompletableFuture除了提供了acceptEither方法,还提供了两个异步方法acceptEitherAsync,一个是使用默认线程池进行异步计算,一个是使用自定义线程池进行异步计算。
CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)
CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action)
CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor)