【发布时间】:2014-06-27 19:27:30
【问题描述】:
假设我有一些异步计算,例如:
CompletableFuture
.supplyAsync(() -> createFoo())
.thenAccept(foo -> doStuffWithFoo(foo));
如果异步供应商根据某些指定的超时超时,是否有一种很好的方法可以为 foo 提供默认值?理想情况下,此类功能也会尝试取消运行缓慢的供应商。例如,是否有类似于以下假设代码的标准库功能:
CompletableFuture
.supplyAsync(() -> createFoo())
.acceptEither(
CompletableFuture.completedAfter(50, TimeUnit.MILLISECONDS, DEFAULT_FOO),
foo -> doStuffWithFoo(foo));
或者甚至更好:
CompletableFuture
.supplyAsync(() -> createFoo())
.withDefault(DEFAULT_FOO, 50, TimeUnit.MILLISECONDS)
.thenAccept(foo -> doStuffWithFoo(foo));
我知道get(timeout, unit),但我想知道是否有更好的标准方法以异步和反应方式应用超时,如上面的代码中所建议的那样。
编辑:这是一个受Java 8: Mandatory checked exceptions handling in lambda expressions. Why mandatory, not optional? 启发的解决方案,但不幸的是它阻塞了一个线程。如果我们依赖 createFoo() 来异步检查超时并抛出它自己的超时异常,它会在不阻塞线程的情况下工作,但会给供应商的创建者带来更多负担,并且仍然会产生创建异常的成本(这可以没有“快速投掷”就很贵)
static <T> Supplier<T> wrapped(Callable<T> callable) {
return () -> {
try {
return callable.call();
} catch (RuntimeException e1) {
throw e1;
} catch (Throwable e2) {
throw new RuntimeException(e2);
}
};
}
CompletableFuture
.supplyAsync(wrapped(() -> CompletableFuture.supplyAsync(() -> createFoo()).get(50, TimeUnit.MILLISECONDS)))
.exceptionally(e -> "default")
.thenAcceptAsync(s -> doStuffWithFoo(foo));
【问题讨论】: