2017-02-20 178 views
2

我遇到了一个奇怪的情况。我与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 

现在,很明显,这段代码并没有真正的产值,但是这是代码的嵌套数量未知的情况,其中每个或其中一些创建了不会执行的嵌套。

任何解释(和示例如何修复),将不胜感激

+1

你可能不希望有嵌套期货这样的。你应该看看['ThenCompose [Async]()'](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#thenCompose-java.util .function.Function-)。 –

回答

1

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

当您拨打completableFutureCompletableFuture.get()时,只保证期货的第一次嵌套完成。 VM退出,并且所有线程都被终止。

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

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

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

+0

谢谢。有效。 –

2

只是测试这和它的作品。我认为为什么不能为你工作的原因是因为你用主要方法运行,而你没有等待完成。在你的代码完成后,我做了一个Thread.sleep(1000)。最好的办法是终止:completableFutureCompletableFuture.get().get().get().get().get()

+0

谢谢。看我的编辑。问题依然存在。 –

+0

@GuyGrin得到只会等第一个任务完成 – user1121883

+0

谢谢。有效。 –

0

发生这种情况是因为你的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