2017-02-20 200 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