2016-05-02 572 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的'有趣的部分'吗? –

相关问题