博文目录
CompletableFuture 使用详解
CompletableFuture基本用法
// Future: 用于表示异步计算的结果。提供了检查计算是否完成、等待其完成以及取回计算结果的方法。T:get方法返回的结果的类型
// CompletionStage: 异步计算的某个阶段,前一个阶段完成时,该阶段开始执行操作或计算值。一个阶段在其计算终止时被称作完成,但是这个完成又可能触发其他的从属阶段。该接口定义了异步计算流程中的不同阶段间的联动操作规范
// CompletableFuture: 可以显式地完成(设置它的值和状态),可以作为CompletionStage来使用,并且支持在完成时触发依赖函数和操作的一个Future的实现
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {}
函数式接口 (Functional Interface) 就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为 lambda 表达式。
表示一个有输入有输出的函数
// Function, 参数是T, 结果是R
public interface Function<T, R> {
R apply(T t);
}
// BiFunction, 参数是T和U, 结果是R
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}
// LongFunction, 参数是long, 结果是R
public interface LongFunction<R> {
R apply(long value);
}
// LongToIntFunction, 参数是long, 结果是int
public interface LongToIntFunction {
int applyAsInt(long value);
}
// LongToDoubleFunction, 参数是long, 结果是double
public interface LongToDoubleFunction {
double applyAsDouble(long value);
}
// ToLongFunction, 参数是T, 结果是long
public interface ToLongFunction<T> {
long applyAsLong(T value);
}
// ToLongBiFunction, 参数是T和U, 结果是long
public interface ToLongBiFunction<T, U> {
long applyAsLong(T t, U u);
}
// 类似Long系Function的还有Int和Double两套
表示一个有输入没有输出的函数
// Consumer, 参数是T, 没有返回值
public interface Consumer<T> {
void accept(T t);
}
// BiConsumer, 参数是T和U, 没有返回值
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
// LongConsumer, 参数是long, 没有返回值
public interface LongConsumer {
void accept(long value);
}
// ObjLongConsumer, 参数是T和long, 没有返回值
public interface ObjLongConsumer<T> {
void accept(T t, long value);
}
// 类似Long系Consumer的还有Int和Double两套
表示一个没有输入有输出的函数
// Supplier, 没有参数, 结果是T
public interface Supplier<T> {
T get();
}
// LongSupplier, 没有参数, 结果是long
public interface LongSupplier {
long getAsLong();
}
// 类似Long系Consumer的还有Int和Double和Boolean三套
表示一个有输入有输出且输出是boolean类型的函数, 副词
// Predicate, 参数是T, 结果是boolean
public interface Predicate<T> {
boolean test(T t);
}
// BiPredicate, 参数是T和U, 结果是boolean
public interface BiPredicate<T, U> {
boolean test(T t, U u);
}
// LongPredicate, 参数是long, 结果是boolean
public interface LongPredicate {
boolean test(long value);
}
// 类似Long系Predicate的还有Int和Double两套
表示一个有输入有输出且入参和结果类型相同的函数, 继承自Function
// UnaryOperator, 一元操作, 一个入参一个出参且类型都一样
public interface UnaryOperator<T> extends Function<T, T> {}
// BinaryOperator, 二元操作, 两个入参一个出参且类型都一样
public interface BinaryOperator<T> extends BiFunction<T,T,T> {}
// LongUnaryOperator, 一元操作, 一个入参一个出参且类型都是long
public interface LongUnaryOperator {
long applyAsLong(long operand);
}
// LongBinaryOperator, 二元操作, 两个入参一个出参且类型都是long
public interface LongBinaryOperator {
long applyAsLong(long left, long right);
}
// 类似Long系Operator的还有Int和Double两套
表示一个没有输入没有输出的函数
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<T> future = new CompletableFuture<T>();
// 当future状态转为完成时回调该方法, value是返回值, cause是Throwable, 如果cause不是null则说明执行报错了, 否则就是正常执行
future.whenComplete((value, cause) -> {
log.info(null != cause ? cause.getMessage() : value);
});
// 使用线程池跑异步任务
executor.execute(() -> {
try {
TimeUnit.SECONDS.sleep(2);
// future 未完成时, 设置 get 或 相关方法 的返回值对象, 并且将该 future 转为完成状态
future.complete("SUCCESS");
} catch (Throwable cause) {
// future 未完成时, 设置发生异常的原因, 并且将该 future 转为完成状态
future.completeExceptionally(cause);
}
});
executor.shutdown();
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)
没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同。
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
private static final String SUCCESS = "success";
@Test
public void init() throws Throwable {
CompletableFuture<Void> runAsyncFuture = CompletableFuture.runAsync(() -> {
log.info("start");
ThreadKit.sleepSecond(1);
log.info("finish");
});
log.info("{}", runAsyncFuture.get());
System.out.println();
CompletableFuture<Void> runAsyncFutureWithExecutor = CompletableFuture.runAsync(() -> {
log.info("start");
ThreadKit.sleepSecond(1);
log.info("finish");
}, executor);
log.info("{}", runAsyncFutureWithExecutor.get());
System.out.println();
CompletableFuture<String> supplyAsyncFuture = CompletableFuture.supplyAsync(() -> {
log.info("start");
ThreadKit.sleepSecond(1);
log.info("finish");
return SUCCESS;
});
log.info("{}", supplyAsyncFuture.get());
System.out.println();
CompletableFuture<String> supplyAsyncFutureWithExecutor = CompletableFuture.supplyAsync(() -> {
log.info("start");
ThreadKit.sleepSecond(1);
log.info("finish");
return SUCCESS;
}, executor);
log.info("{}", supplyAsyncFutureWithExecutor.get());
executor.shutdown();
}
[20210204.164541.643][INFO ][ForkJoinPool.commonPool-worker-1] start
[20210204.164542.648][INFO ][ForkJoinPool.commonPool-worker-1] finish
[20210204.164542.648][INFO ][main] null
[20210204.164542.650][INFO ][pool-2-thread-1] start
[20210204.164543.650][INFO ][pool-2-thread-1] finish
[20210204.164543.650][INFO ][main] null
[20210204.164543.653][INFO ][ForkJoinPool.commonPool-worker-1] start
[20210204.164544.653][INFO ][ForkJoinPool.commonPool-worker-1] finish
[20210204.164544.653][INFO ][main] success
[20210204.164544.654][INFO ][pool-2-thread-1] start
[20210204.164545.654][INFO ][pool-2-thread-1] finish
[20210204.164545.654][INFO ][main] success
当上个阶段正常结束或抛出异常的时候,接收上个阶段的结果和异常,作为入参接着执行该阶段,该阶段没有返回值(即下下个阶段如果需要拿到该阶段的结果是null)
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)
whenComplete 和 whenCompleteAsync 的区别:
其他类似方法也是同样的规则
BiConsumer super T, ? super Throwable>, 代表两个入参没有出参的函数,第一个参数是上个阶段的结果,第二个参数是上个阶段的异常。如果上个阶段正常结束,则异常为null,如果上个阶段异常,则异常不为null。如果上个阶段正常结束且没有返回值,则第一个参数为null
当上个阶段正常结束的时候,接收上个阶段的结果,作为入参接着执行该阶段,该阶段有返回值。如果上个阶段异常则该阶段不再执行
Function super T, ? extends U>,代表一个入参一个出参的函数,入参是上个阶段的结果,出错的话会报异常
和 whenComplete 一样,只是有返回值。当上个阶段正常结束或抛出异常的时候,接收上个阶段的结果和异常,作为入参接着执行该阶段,该阶段有返回值
BiFunction super T, Throwable, ? extends U>,代表两个入参一个出参的函数,第一个参数是上个阶段的结果,第二个参数是上个阶段的异常。
和 thenApply 一样,只是没有返回值
Consumer super T>,代表一个入参没有出参的函数,入参是上个阶段的结果
当上个阶段正常结束或抛出异常的时候,接着执行该阶段,不接收上个阶段的结果或异常,也不返回结果
Runnable,代表没有入参没有出参的函数
和 thenApply 一样,不过要求返回结果的类型是一个新的阶段,而不是由工具帮忙包装成一个阶段
Function super T, ? extends CompletionStage>
当两个独立阶段都正常执行结束时,接收这两个阶段的结果,作为入参接着执行该阶段,该阶段有返回值
BiFunction super T,? super U,? extends V>
和 thenCombine 一样,只是没有返回值
BiConsumer super T, ? super U>
以两个独立阶段中先正常执行结束的那个阶段的结果作为入参接着执行该阶段,有返回值
Function super T, U>
和 applyToEither 一样,只是没有返回值
Consumer super T>
两个独立阶段任何一个正常执行结束,接着执行该阶段,不接收其结果或异常,也不返回结果
Runnable
两个独立阶段都正常执行结束,才接着执行该阶段,不接收其结果或异常,也不返回结果
Runnable
package jdk.java.util.concurrent;
import com.mrathena.toolkit.ThreadKit;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
public class CompletableFutureTest {
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
private static final String SUCCESS = "success";
@Test
public void runAfterBoth() throws Throwable {
Random random = new Random();
CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
int seconds = random.nextInt(3);
log.info("{}", seconds);
ThreadKit.sleepSecond(seconds);
return "1";
});
CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
int seconds = random.nextInt(3);
log.info("{}", seconds);
ThreadKit.sleepSecond(seconds);
return "2";
});
CompletableFuture<Void> future = firstFuture.runAfterBoth(secondFuture, () -> log.info("finish"));
ThreadKit.sleepSecond(3);
}
@Test
public void runAfterEither() throws Throwable {
Random random = new Random();
CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
int seconds = random.nextInt(3);
log.info("{}", seconds);
ThreadKit.sleepSecond(seconds);
return "1";
});
CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
int seconds = random.nextInt(3);
log.info("{}", seconds);
ThreadKit.sleepSecond(seconds);
return "2";
});
CompletableFuture<Void> future = firstFuture.runAfterEither(secondFuture, () -> log.info("finish"));
ThreadKit.sleepSecond(3);
}
@Test
public void acceptEither() throws Throwable {
Random random = new Random();
CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
int seconds = random.nextInt(3);
log.info("{}", seconds);
ThreadKit.sleepSecond(seconds);
return "1";
});
CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
int seconds = random.nextInt(3);
log.info("{}", seconds);
ThreadKit.sleepSecond(seconds);
return "2";
});
CompletableFuture<Void> future = firstFuture.acceptEither(secondFuture, System.out::println);
ThreadKit.sleepSecond(3);
}
@Test
public void applyToEither() throws Throwable {
Random random = new Random();
CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
int seconds = random.nextInt(3);
log.info("{}", seconds);
ThreadKit.sleepSecond(seconds);
return "1";
});
CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
int seconds = random.nextInt(3);
log.info("{}", seconds);
ThreadKit.sleepSecond(seconds);
return "2";
});
CompletableFuture<String> future = firstFuture.applyToEither(secondFuture, fastFutureResult -> fastFutureResult);
log.info(future.get());
}
@Test
public void thenAcceptBoth() throws Throwable {
CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
log.info("first stage finish");
return "the result of first stage";
});
ThreadKit.sleepSecond(2);
System.out.println();
CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
log.info("first stage finish");
return "the result of first stage";
});
CompletableFuture<Void> future = firstFuture.thenAcceptBoth(secondFuture,
(firstStageResult, secondStageResult) -> {System.out.println(firstStageResult + " + " + secondStageResult);});
ThreadKit.sleepSecond(2);
}
@Test
public void thenCompose() throws Throwable {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
log.info("first stage finish");
return "the result of first stage";
}).thenCompose(lastStageResult -> CompletableFuture.supplyAsync(() -> {
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
return "the result of first stage";
}));
log.info(future.get());
}
@Test
public void thenCombine() throws Throwable {
CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
log.info("first stage finish");
return "the result of first stage";
});
ThreadKit.sleepSecond(2);
System.out.println();
CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
return "the result of first stage";
});
CompletableFuture<String> future = firstFuture.thenCombine(secondFuture,
(firstStageResult, secondStageResult) -> firstStageResult + " + " + secondStageResult);
log.info(future.get());
}
@Test
public void thenRun() throws Throwable {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
log.info("first stage finish");
return "the result of first stage";
}).thenRun(() -> {
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
});
ThreadKit.sleepSecond(3);
System.out.println();
CompletableFuture<Void> throwableFuture = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
int a = 10 / 0;
log.info("first stage finish");
return "the result of first stage";
}).thenRun(() -> {
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
});
ThreadKit.sleepSecond(3);
}
@Test
public void thenAccept() throws Throwable {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
log.info("first stage finish");
return "the result of first stage";
}).thenAccept(lastStageResult -> {
log.info(lastStageResult);
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
});
ThreadKit.sleepSecond(3);
System.out.println();
CompletableFuture<Void> throwableFuture = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
int a = 10 / 0;
log.info("first stage finish");
return "the result of first stage";
}).thenAccept(lastStageResult -> {
log.info(lastStageResult);
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
});
ThreadKit.sleepSecond(3);
}
@Test
public void handle() throws Throwable {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
log.info("first stage finish");
return SUCCESS;
}).handle((lastStageResult, lastStageCause) -> {
log.info("{}, {}", lastStageResult, null == lastStageCause ? null : lastStageCause.getMessage());
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
return "the result of second stage";
});
log.info(future.get());
System.out.println();
CompletableFuture<String> throwableFuture = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
int a = 10 / 0;
log.info("first stage finish");
return SUCCESS;
}).handle((lastStageResult, lastStageCause) -> {
log.info("{}, {}", lastStageResult, lastStageCause.getMessage());
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
return "the result of second stage";
});
try {
log.info(throwableFuture.get());
} catch (Throwable cause) {
log.info(cause.getMessage());
}
}
@Test
public void thenApply() throws Throwable {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
log.info("first stage finish");
return "the result of first stage";
}).thenApply(lastStageResult -> {
log.info(lastStageResult);
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
return "the result of second stage";
});
log.info(future.get());
System.out.println();
CompletableFuture<String> throwableFuture = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
int a = 10 / 0;
log.info("first stage finish");
return "the result of first stage";
}).thenApply(lastStageResult -> {
log.info(lastStageResult);
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
return "the result of second stage";
});
// 一个阶段出错的话, 该阶段剩下的代码不再执行, 后续的阶段也不再执行, 在get的时候会报错
try {
log.info(throwableFuture.get());
} catch (Throwable cause) {
log.info(cause.getMessage());
}
}
@Test
public void whenComplete() throws Throwable {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
log.info("first stage finish");
return SUCCESS;
}).whenComplete((lastStageResult, lastStageCause) -> {
log.info("{}, {}", lastStageResult, null == lastStageCause ? null : lastStageCause.getMessage());
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
});
// whenComplete没有提供返回值, 这里取到的是整个流程的所有阶段中, 最后一个有返回值的阶段返回的值
log.info(future.get());
System.out.println();
CompletableFuture<String> throwableFuture = CompletableFuture.supplyAsync(() -> {
log.info("first stage start");
ThreadKit.sleepSecond(1);
int a = 10 / 0;
log.info("first stage finish");
return SUCCESS;
}).whenComplete((lastStageResult, lastStageCause) -> {
log.info("{}, {}", lastStageResult, lastStageCause.getMessage());
log.info("second stage start");
ThreadKit.sleepSecond(1);
log.info("second stage finish");
});
// 一个阶段出错的话, 该阶段剩下的代码不再执行, 但后续的阶段可以继续执行, 在get的时候会报错
try {
log.info(throwableFuture.get());
} catch (Throwable cause) {
log.info(cause.getMessage());
}
}
@Test
public void init() throws Throwable {
CompletableFuture<Void> runAsyncFuture = CompletableFuture.runAsync(() -> {
log.info("start");
ThreadKit.sleepSecond(1);
log.info("finish");
});
log.info("{}", runAsyncFuture.get());
System.out.println();
CompletableFuture<Void> runAsyncFutureWithExecutor = CompletableFuture.runAsync(() -> {
log.info("start");
ThreadKit.sleepSecond(1);
log.info("finish");
}, executor);
log.info("{}", runAsyncFutureWithExecutor.get());
System.out.println();
CompletableFuture<String> supplyAsyncFuture = CompletableFuture.supplyAsync(() -> {
log.info("start");
ThreadKit.sleepSecond(1);
log.info("finish");
return SUCCESS;
});
log.info("{}", supplyAsyncFuture.get());
System.out.println();
CompletableFuture<String> supplyAsyncFutureWithExecutor = CompletableFuture.supplyAsync(() -> {
log.info("start");
ThreadKit.sleepSecond(1);
log.info("finish");
return SUCCESS;
}, executor);
log.info("{}", supplyAsyncFutureWithExecutor.get());
executor.shutdown();
}
}