Java异步执行器CompletableFuture(Jdk9)改进
一、概述
CompletableFuture现有功能可以满足我们诉求。但当我们引入一些现实常见情况时,一些潜在的不足便暴露出来了。
Java9对CompletableFuture类进行了一些更改。这些更改是作为JEP 266的一部分引入的,CompletableFuture正式提供了orTimeout、completeTimeout方法,来准确实现异步超时控制。
二、实例新添加的API
2.1. defaultExecutor()
public Executor defaultExecutor() {
return ASYNC_POOL;
}
返回用于未指定执行程序的异步方法的默认Executor。
这可以通过返回至少提供一个独立线程的Executor的子类来覆盖。
2.2. newIncompleteFuture()
public <U> CompletableFuture<U> newIncompleteFuture() {
return new CompletableFuture<U>();
}
newIncompleteFuture,也称为“虚拟构造函数”,用于获取相同类型的新可完成未来实例。
此方法在子类化CompletableFuture时特别有用,主要是因为它在几乎所有返回新CompletionStage的方法中内部使用,允许子类控制这些方法返回的子类型。
2.3. copy()
public CompletableFuture<T> copy() {
return uniCopyStage(this);
}
这个方法返回一个新的CompletableFuture
- 当这个正常完成时,新的也正常完成
- 当它以异常X异常完成时,新的一个也以异常完成,并以X作为原因的
CompletionException
此方法可能用作“防御性复制”的一种形式,以防止客户端完成,同时仍然能够在CompletableFuture的特定实例上安排依赖操作。
2.4. minimalCompletionStage()
public CompletionStage<T> minimalCompletionStage() {
return uniAsMinimalStage();
}
此方法返回一个新的CompletionStage,其行为方式与复制方法描述的方式完全相同,但是,此类新实例在每次尝试检索或设置解析值时都会引发UnsupportedOperationException。
可以使用CompletionStageAPI上提供的toCompletableFuture方法检索包含所有可用方法的新CompletableFuture。
2.5. completeAsync()
应使用completeAsync方法,使用供应商提供的值异步完成CompletableFuture。
public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier,
Executor executor) {
if (supplier == null || executor == null)
throw new NullPointerException();
executor.execute(new AsyncSupply<T>(this, supplier));
return this;
}
public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier) {
return completeAsync(supplier, defaultExecutor());
}
这两个重载方法之间的区别在于存在第二个参数,可以在其中指定运行任务的执行器。如果未提供任何内容,则将使用默认执行器(由defaultExecutor方法返回)。
2.6. orTimeout()
public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit) {
if (unit == null)
throw new NullPointerException();
if (result == null)
whenComplete(new Canceller(Delayer.delay(new Timeout(this),
timeout, unit)));
return this;
}
使用TimeoutException异常解析CompletableFuture,除非它在指定的超时之前完成。
2.7.completeOnTimeout()
public CompletableFuture<T> completeOnTimeout(T value, long timeout,
TimeUnit unit) {
if (unit == null)
throw new NullPointerException();
if (result == null)
whenComplete(new Canceller(Delayer.delay(
new DelayedCompleter<T>(this, value),
timeout, unit)));
return this;
}
使用指定的值正常完成CompletableFuture,除非它在指定的超时之前完成。
三、静态API添加
还添加了一些实用程序方法
3.1. delayedExecutor
public static Executor delayedExecutor(long delay, TimeUnit unit,
Executor executor) {
if (unit == null || executor == null)
throw new NullPointerException();
return new DelayedExecutor(delay, unit, executor);
}
public static Executor delayedExecutor(long delay, TimeUnit unit) {
if (unit == null)
throw new NullPointerException();
return new DelayedExecutor(delay, unit, ASYNC_POOL);
}
返回一个新的执行程序,该执行程序在给定延迟后(如果为非正值,则无延迟)向给定的基本执行程序提交任务。每个延迟在调用返回的执行程序的执行方法时开始。如果未指定执行器,则将使用默认执行器(ForkJoinPool.commonPool())。
3.2. completedStage与failedStage
public static <U> CompletionStage<U> completedStage(U value) {
return new MinimalStage<U>((value == null) ? NIL : value);
}
public static <U> CompletionStage<U> failedStage(Throwable ex) {
if (ex == null) throw new NullPointerException();
return new MinimalStage<U>(new AltResult(ex));
}
此实用工具方法返回已解析的CompletionStage实例,这些实例要么正常完成,但有值(completeStage),要么异常完成(failedStage),但出现给定的异常。
3.3. failedFuture
public static <U> CompletableFuture<U> failedFuture(Throwable ex) {
if (ex == null) throw new NullPointerException();
return new CompletableFuture<U>(new AltResult(ex));
}
failedFuture方法添加了指定已完成的异常CompletableFuture实例的功能。
四、案例
在本节中,我们将展示一些有关如何使用一些新API的示例。
public class CompletableFutureTest {
public void testOrTimeout() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = new CompletableFuture<>();
future.orTimeout(1, TimeUnit.SECONDS);
ExecutionException exception = assertThrows(ExecutionException.class, () -> {
future.get(); // 任务未完成,预期抛出 TimeoutException
});
Throwable cause = exception.getCause();
assertThrows(java.util.concurrent.TimeoutException.class, cause::getClass);
}
public void testCompleteOnTimeout() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = new CompletableFuture<>();
future.completeOnTimeout("default", 1, TimeUnit.SECONDS);
assertEquals("default", future.get()); // 预期结果为 "default"
}
public void testOrTimeoutAndCompleteOnTimeout() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = new CompletableFuture<>();
future.completeAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500); // 模拟耗时任务
} catch (InterruptedException e) {
e.printStackTrace();
}
return "result";
});
future.orTimeout(1, TimeUnit.SECONDS);
future.completeOnTimeout("default", 1, TimeUnit.SECONDS);
assertEquals("result", future.get()); // 预期结果为 "result"
}
public void testCompleteOnTimeoutBeforeCompletion() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = new CompletableFuture<>();
future.completeAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500); // 模拟耗时任务
} catch (InterruptedException e) {
e.printStackTrace();
}
return "result";
});
future.completeOnTimeout("default", 1, TimeUnit.SECONDS);
assertEquals("result", future.get()); // 预期结果为 "result"
}
}
五、总结
本文介绍了CompletableFuture现有功能的不足,以及新添加的API,并提供了示例用例。希望这些新API能够帮助我们更好地管理异步任务的执行。
六、拓展
JDK8异步工具类
如果我们使用的是JDK 9或以上,我们可以直接用JDK的实现来完成异步超时操作。那么JDK 8怎么办呢?
其实我们也可以根据上述逻辑简单实现一个工具类来辅助。
public class CompletableFutureTest {
public CompletionStage<Response> orderCompletionStage() {
Response resp = new Response();
return CompleteFutureExtendUtil.orTimeout(CompletableFuture.supplyAsync(() -> {
try {
resp.setErrorCode("0");
resp.setValue("success");
resp.setData("order");
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
return resp;
}), 2, TimeUnit.SECONDS)
.exceptionally(throwable -> {
resp.setErrorCode("1");
resp.setValue("error");
resp.setData("order");
return resp;
});
}
@Data
class Response {
private String errorCode;
private String value;
private Object data;
}
static class CompleteFutureExtendUtil {
public static <T> CompletableFuture<T> orTimeout(CompletableFuture<T> future,
long timeout, TimeUnit unit) {
final CompletableFuture<T> timeoutFuture = timeoutAfter(timeout, unit);
// 哪个先完成 就apply哪一个结果
return future.applyToEither(timeoutFuture, Function.identity());
}
public static <T> CompletableFuture<T> timeoutAfter(long timeout, TimeUnit unit) {
CompletableFuture<T> result = new CompletableFuture<T>();
// timeout 时间后 抛出TimeoutException 类似于sentinel / watcher
Delayer.delayer.schedule(() -> result.completeExceptionally(new TimeoutException()), timeout, unit);
return result;
}
/**
* 单例延迟调度器,仅用于启动和取消任务,一个线程就足够
*/
static final class Delayer {
static ScheduledFuture<?> delay(Runnable command, long delay,
TimeUnit unit) {
return delayer.schedule(command, delay, unit);
}
static final class DaemonThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("CompletableFutureDelayScheduler");
return t;
}
}
static final ScheduledThreadPoolExecutor delayer;
// 注意,这里使用一个线程就可以搞定 因为这个线程并不真的执行请求 而是仅仅抛出一个异常
static {
(delayer = new ScheduledThreadPoolExecutor(
1, new DaemonThreadFactory())).
setRemoveOnCancelPolicy(true);
}
}
}
}

浙公网安备 33010602011771号