2017-07-03 113 views
1

我想了解CompletableFuture接口的Java 8 我當前的代碼是:CompletableFuture:異步調用,處理結果在當前線程後

CompletableFuture.supplyAsync(() -> wachtwoordBijwerken(gebruikersnaam, wachtwoord)) 
    .thenAccept(this::saveOrUpdateGebruiker) 
    .exceptionally(e -> 
    { 
     log.error("Fout bij het bijwerken van wachtwoord voor gebruiker: " + gebruikersnaam, e); 
     return null; 
    }); 

我預計呼叫saveOrUpdateGebruiker()在主線程中運行新創建的線程中的異步調用完成後。 但是,調用仍在另一個線程中,這會導致底層hibernate實現中出現問題。

有沒有辦法將CompletableFuture用於非阻塞異步調用,並且仍然能夠在當前線程中使用結果?

回答

2

不自動沒有。當執行由CompletableFuturesupplyAsyncthenAccept等提供的操作時,它們全部由線程池中的線程執行。這可以讓你在你認爲合適的情況下在主線程中進行「火和忘」操作並繼續工作。

如果要在CompletableFuture完成後在當前線程中執行工作,則需要等待並使用isDone()和/或get()方法檢查其完成情況。

但是,如果您這樣做,那麼在正常的Future(例如FutureTask)上使用CompletableFuture沒有任何優勢。

+0

所以最後,結果是阻塞同步調用? (因爲get()函數) – Cloud

+1

那麼,除非你輪詢'isDone()'。這是您可以在當前線程上運行的唯一方法。 – Kayaman

1

您可以使用它使用您在參數傳遞執行人執行回調,這也可以是最終相同的是,一個你有來電

一樣,該方法thenAcceptAsync(Runnable, Executor),可以控制線程用於執行您的回調代碼

也見/執行人:This related Stackoverflow question

+1

這裏有兩個相互矛盾的答案。也許你應該修改你的答案,因爲答案不是「是」,答案是「不,你不能在**當前線程**中運行它」。否則答案是好的。 – Kayaman

+0

不幸的是,這是不正確的。即使使用執行器技巧,也無法讓代碼在您調用'supplyAsync'的同一線程上運行。相關問題描述了一個將在當前線程上運行的執行程序,但是這個問題是關於當前線程,一個線程在池中(運行'supplyAsync'),並最終在當前線程中再次運行。如果提供描述的執行程序,它將是運行它的池線程(因爲它是當前的「當前線程」)。 – Kayaman

1

使用CompletableFuture是您的方案矯枉過正。 CompletableFuture在其設計中是非阻塞的,當作業完成時,可以使用join()或輪詢isDone()方法來收集結果,然後執行同步操作。如果只有一個進程繼續向專用的ThreadPool發送任務,則使用CompletableFuture比CompletionServiceExecutorService沒有任何優勢。我寫了一個簡單的博客,其中CompletableFuture與傳統的Threadpool相比非常合適:https://medium.com/@zhongzhongzhong/beauty-of-completablefuture-and-where-should-you-use-it-6ac65b7bfbe