我正在创建一些任务,如下所示(这只是为了演示正常的网络调用):
public class RandomTask implements Function<String, String> {
private int number;
private int waitTime;
private boolean throwError;
public RandomTask(int number, int waitTime, boolean throwError) {
this.number = number;
this.waitTime = waitTime;
this.throwError = throwError;
}
@Override
public String apply(String s) {
System.out.println("Job " + number + " started");
try {
Thread.sleep(waitTime);
if (throwError) {
throw new InterruptedException("Something happened");
}
} catch (InterruptedException e) {
System.out.println("Error " + e.getLocalizedMessage());
}
return "RandomTask " + number + " finished";
}
}
然后我有一个Chain类,其中每个作业将一些任务链接在一起。
static CompletableFuture<String> start(ExecutorService executorService) {
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Foo", executorService)
.thenApplyAsync(new RandomTask(3, 100, false), executorService)
.thenApplyAsync(new RandomTask(4, 100, false), executorService);
return future2;
}
然后我按如下所示开始两条链:
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(Chain1.start(fixedThreadPool), Chain2.start(fixedThreadPool));
try {
combinedFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
这样,两条链就同时开始了。
现在,我想在任务中引发异常,并在调用CombinedFuture.get()的地方捕获该异常,以便我知道链中哪个任务失败了。
问题是,我无法适应Function,因为CompletableFutures对此有所抱怨。我尝试过:
@FunctionalInterface
public interface CheckedFunction<T, R> {
R apply(T t) throws InterruptedException;
}
但这不起作用。这是不可能的,还是我如何实现我的目标?
答案 0 :(得分:1)
“这样,两条链就同时开始了。”表明您对CompletableFuture
的工作原理有根本的错误认识。
异步操作在创建时或在其先决条件可用时立即提交给执行者服务。因此,对于supplyAsync
没有依赖性的情况,异步操作直接在supplyAsync
调用内开始。
所有类似CompletableFuture.allOf(job1, job2).get()
的构造,都是根据两个作业创建一个新阶段并等待其完成,因此最终结果只是等待两个作业的完成。它不会不启动作业。他们已经在运行。等待完成不会影响完成过程。
使用允许检查异常的自定义函数类型绑定CompletableFuture
可以
public static <T,R> CompletableFuture<R> thenApplyAsync(
CompletableFuture<T> f, CheckedFunction<? super T, ? extends R> cf,
Executor e) {
CompletableFuture<R> r = new CompletableFuture<>();
f.whenCompleteAsync((v,t) -> {
try {
if(t != null) r.completeExceptionally(t);
else r.complete(cf.apply(v));
} catch(Throwable t2) {
r.completeExceptionally(t2);
}
}, e);
return r;
}
要使用此方法,您不必嵌套CompletableFuture
上的调用,而必须嵌套它们。例如
static CompletableFuture<String> start(ExecutorService executorService) {
CompletableFuture<String> future2 =
thenApplyAsync(thenApplyAsync(
CompletableFuture.supplyAsync(() -> "Foo", executorService),
new RandomTask(3, 100, false), executorService),
new RandomTask(4, 100, false), executorService);
return future2;
}
给予
public class RandomTask implements CheckedFunction<String, String> {
private int number, waitTime;
private boolean throwError;
public RandomTask(int number, int waitTime, boolean throwError) {
this.number = number;
this.waitTime = waitTime;
this.throwError = throwError;
}
@Override
public String apply(String s) throws InterruptedException {
System.out.println("Job " + number + " started");
Thread.sleep(waitTime);
if (throwError) {
throw new InterruptedException("Something happened in "+number);
}
return "RandomTask " + number + " finished";
}
}
您仍然可以创建两个任务,然后等待两个任务
CompletableFuture.allOf(Chain1.start(fixedThreadPool), Chain2.start(fixedThreadPool))
.join();