2016-05-02 81 views
4

我在CompletableFuture的supplyAsync()中處理長時間運行的操作,並將結果導入到thenAccept()中。在某些時候,接受()在主線程上執行,但有一段時間它在工作線程上運行。但是我想僅在主線程上運行thenAccept()操作。這是示例代碼。爲什麼CompletableFuture的thenAccept()未在主線程上運行

private void test() { 

    ExecutorService executorService = Executors.newSingleThreadExecutor(); 

    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> { 
     System.out.println("supplyAsync | I am running on : " + Thread.currentThread().getName()); 
     return "Hello world"; 
    }, executorService); 

    CompletableFuture<Void> cf3 = cf1.thenAccept(s -> { 
     System.out.print("thenAccept | I am running on : " + Thread.currentThread().getName()); 
     System.out.println(" | answer : " + s); 
    }); 

    cf3.thenRun(() -> { 
     System.out.println("thenRun | I am running on : " + Thread.currentThread().getName()); 
     System.out.println(); 
    }); 

} 

public static void main(String[] args) { 

    App app = new App(); 
    for(int i = 0; i < 3; i++){ 
     app.test(); 
    } 
} 

結果是:

supplyAsync | I am running on : pool-1-thread-1 
thenAccept | I am running on : main | answer : Hello world 
thenRun | I am running on : main 

supplyAsync | I am running on : pool-2-thread-1 
thenAccept | I am running on : main | answer : Hello world 
thenRun | I am running on : main 

supplyAsync | I am running on : pool-3-thread-1 
thenAccept | I am running on : pool-3-thread-1 | answer : Hello world 
thenRun | I am running on : pool-3-thread-1 

我怎樣才能解決這個問題?

+0

你爲什麼想這樣做? – sisyphus

+0

謝謝。假設我在訪問共享資源的方法中使用了thenAccept()方法。然後我必須考慮資源的線程安全性。 Vert.x的executeBlocking與此類似。他們正確處理這一點。 – Tharanga

+0

那麼,'正確'可能在旁觀者的眼中。如果您以異步方式訪問共享資源,您似乎需要關注線程安全性。也許你應該只允許通過監視器訪問共享資源,該監視器在單個線程上調度任務。 – sisyphus

回答

1

看看CompletableFuture的JavaDoc。有趣的部分是有關CompletionStage政策的。

在那裏您會發現使用非異步方法會產生一種任意或場景。如果您接下來看一下實現,您將最終進入Java運行時的非公開部分。有一些UNSAFE處理,這意味着可能會發生某種競爭條件。

)我會建議使用thenAcceptAsync(thenRunAsync()變種和你的ExecutorService變量傳遞給兩個呼叫。

+0

在完成所有'CompletableFuture'任務之前主線程是否退出?另外,你可以發佈'CompletableFuture' javadoc的'有趣的部分'嗎? –

相關問題