嵌套期货不执行
Nested Futures not executing
我遇到了一个奇怪的情况。我在摆弄 CompletableFuture
,当 运行 以下代码时,我得到了意想不到的结果:
public static void main(String[] args) {
CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<Object>>>>>> completableFutureCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("first");
return CompletableFuture.supplyAsync(() -> {
System.out.println("second");
return CompletableFuture.supplyAsync(() -> {
System.out.println("third");
return CompletableFuture.supplyAsync(() -> {
System.out.println("fourth");
return CompletableFuture.supplyAsync(() -> {
System.out.println("fifth");
return CompletableFuture.completedFuture(null);
});
});
});
});
});
completableFutureCompletableFuture.get();
}
没有抛出异常(即使使用 exceptionally
),我看到控制台输出是
first
second
third // appears sometimes
现在,显然这段代码没有真正的生产价值,但这是一种情况,您的代码具有未知数量的嵌套,其中每个或其中一些创建 CompleteableFutures
而不会被执行。
任何解释(以及如何修复的示例)将不胜感激
刚刚测试了这个并且它有效。我认为不适合您的原因是因为您 运行 在主要方法中并且您没有等待完成。我在你的代码之后做了一个 Thread.sleep(1000)
并且它起作用了。最好的方法是等待终止:completableFutureCompletableFuture.get().get().get().get().get()
这不起作用的原因是因为在您的简单测试中,VM 在所有任务完成之前退出。
当您调用 completableFutureCompletableFuture.get()
时,只有第一个期货嵌套可以保证完成。 VM 退出,所有线程都被杀死。
换句话说,第一个嵌套的未来可能仍然是 "uncompleted",因为它的线程可能仍然很忙。但是,当您尝试使用 get
获取结果时,它当然会等到它完成并按预期工作。试试看:
completableFutureCompletableFuture.get().get().get().get().get()
...然后您强制所有期货完成并且一切都按预期进行。
发生这种情况是因为您的 CompletableFuture 是异步执行的,但您的程序在第五次调用发生之前终止(我假设您 运行 它在一个主程序中并在创建您的期货后立即返回)。
因为您可能不知道您的 Future 中堆叠了多少 Future(由于类型擦除)。您可能想要执行递归 .get().
参见:
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<?> futures = getFutures();
recursiveGet(futures);
System.out.println("finished");
}
public static CompletableFuture<?> getFutures() {
CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<Object>>>>>> compositeCompletable = CompletableFuture.supplyAsync(() -> {
System.out.println("first");
return CompletableFuture.supplyAsync(() -> {
System.out.println("second");
return CompletableFuture.supplyAsync(() -> {
System.out.println("third");
return CompletableFuture.supplyAsync(() -> {
System.out.println("fourth");
return CompletableFuture.supplyAsync(() -> {
System.out.println("fifth");
return CompletableFuture.completedFuture(null);
});
});
});
});
});
return compositeCompletable;
}
public static void recursiveGet(Future<?> future) throws InterruptedException, ExecutionException{
Object result = future.get();
if(result instanceof Future){
recursiveGet((Future<?>) result);
}
}
哪个returns
first
second
third
fourth
fifth
finished
我遇到了一个奇怪的情况。我在摆弄 CompletableFuture
,当 运行 以下代码时,我得到了意想不到的结果:
public static void main(String[] args) {
CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<Object>>>>>> completableFutureCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("first");
return CompletableFuture.supplyAsync(() -> {
System.out.println("second");
return CompletableFuture.supplyAsync(() -> {
System.out.println("third");
return CompletableFuture.supplyAsync(() -> {
System.out.println("fourth");
return CompletableFuture.supplyAsync(() -> {
System.out.println("fifth");
return CompletableFuture.completedFuture(null);
});
});
});
});
});
completableFutureCompletableFuture.get();
}
没有抛出异常(即使使用 exceptionally
),我看到控制台输出是
first
second
third // appears sometimes
现在,显然这段代码没有真正的生产价值,但这是一种情况,您的代码具有未知数量的嵌套,其中每个或其中一些创建 CompleteableFutures
而不会被执行。
任何解释(以及如何修复的示例)将不胜感激
刚刚测试了这个并且它有效。我认为不适合您的原因是因为您 运行 在主要方法中并且您没有等待完成。我在你的代码之后做了一个 Thread.sleep(1000)
并且它起作用了。最好的方法是等待终止:completableFutureCompletableFuture.get().get().get().get().get()
这不起作用的原因是因为在您的简单测试中,VM 在所有任务完成之前退出。
当您调用 completableFutureCompletableFuture.get()
时,只有第一个期货嵌套可以保证完成。 VM 退出,所有线程都被杀死。
换句话说,第一个嵌套的未来可能仍然是 "uncompleted",因为它的线程可能仍然很忙。但是,当您尝试使用 get
获取结果时,它当然会等到它完成并按预期工作。试试看:
completableFutureCompletableFuture.get().get().get().get().get()
...然后您强制所有期货完成并且一切都按预期进行。
发生这种情况是因为您的 CompletableFuture 是异步执行的,但您的程序在第五次调用发生之前终止(我假设您 运行 它在一个主程序中并在创建您的期货后立即返回)。
因为您可能不知道您的 Future 中堆叠了多少 Future(由于类型擦除)。您可能想要执行递归 .get().
参见:
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<?> futures = getFutures();
recursiveGet(futures);
System.out.println("finished");
}
public static CompletableFuture<?> getFutures() {
CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<CompletableFuture<Object>>>>>> compositeCompletable = CompletableFuture.supplyAsync(() -> {
System.out.println("first");
return CompletableFuture.supplyAsync(() -> {
System.out.println("second");
return CompletableFuture.supplyAsync(() -> {
System.out.println("third");
return CompletableFuture.supplyAsync(() -> {
System.out.println("fourth");
return CompletableFuture.supplyAsync(() -> {
System.out.println("fifth");
return CompletableFuture.completedFuture(null);
});
});
});
});
});
return compositeCompletable;
}
public static void recursiveGet(Future<?> future) throws InterruptedException, ExecutionException{
Object result = future.get();
if(result instanceof Future){
recursiveGet((Future<?>) result);
}
}
哪个returns
first
second
third
fourth
fifth
finished