嵌套期货未执行

时间:2017-02-20 10:37:51

标签: java multithreading completable-future

我遇到了一个奇怪的情况。我正在摆弄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不会被执行

非常感谢任何解释(以及如何修复的示例)

3 个答案:

答案 0 :(得分:3)

这不起作用的原因是因为在您的简单测试中,VM在所有任务完成之前退出。

当您致电completableFutureCompletableFuture.get()时,只保证期货的第一个嵌套完成。 VM退出,所有线程都被杀死。

换句话说,第一个嵌套的未来可能仍然是“未完成”,因为它的线程可能仍然很忙。但是,当您尝试使用get获取结果时,它当然会等到它完成并且它将按预期工作。试试吧:

completableFutureCompletableFuture.get().get().get().get().get()

...然后你强制所有的期货都已完成,一切都按预期运作。

答案 1 :(得分:2)

刚试过这个就可以了。我认为不适合你的原因是因为你在主方法中运行而你没等到完成。我在你的代码之后做了Thread.sleep(1000)并且它有效。最好的方法是终止:completableFutureCompletableFuture.get().get().get().get().get()

答案 2 :(得分:2)

这是因为您的CompletableFuture是异步执行的,但是您的程序在第五次调用之前终止(我假设您在一个main中运行它并在创建期货后立即返回)。

你可能不知道你的未来有多少未来(由于类型擦除)。您可能想要执行递归.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);
    }
}

返回

first
second
third
fourth
fifth
finished