如果在runAsync调用之后链接,那么RunAsync(与thenRun相反)是否有任何区别?

Apr*_*ohn 3 java java-8 completable-future

在下面的代码中,调用thenRunAsync会有什么不同吗?我应该打电话给那么跑吗?

CompletableFuture.runAsync(this::doWork , executorService)
     .thenRunAsync(this::handleSuccess);
Run Code Online (Sandbox Code Playgroud)

根据评论进行阐述:如果我使用此代码,

CompletableFuture.runAsync(this::doWork , executorService)
     .thenRun(this::handleSuccess);
Run Code Online (Sandbox Code Playgroud)

会有什么不同吗?

在这两种情况下,行为都是非阻塞的,并且无论如何,第二个任务在第一个任务完成之前不会运行,据我所知.

Hol*_*ger 10

如果已经完成,该方法thenRun允许Runnable直接在调用者的线程中执行CompletableFuture.因为即使在直接调用链中,例如CompletableFuture.runAsync(…).thenRun(…);异步任务在thenRun调用时已经完成的可能性,也可能在调用者的线程中执行相关操作,不像那样thenRunAsync将始终使用默认(或提供的)执行程序.

所以在一句话中,是的,它会产生影响.


顺便说一下,使用thenRunAsync(单个参数版本)将不会使用Executor提供给初始工厂调用的操作执行操作,而是默认操作Executor.

您可以轻松比较不同的行为:

public static void main(String[] args) {
    ExecutorService e=Executors.newSingleThreadExecutor(r -> new Thread(r, "sole thread"));
    CompletableFuture<?> f=CompletableFuture.runAsync(()->{}, e);
    f.join();
    f.thenRun(()->System.out.println("thenRun:\t"+Thread.currentThread()));
    f.thenRunAsync(()->System.out.println("thenRunAsync:\t"+Thread.currentThread()));
    f.thenRunAsync(()->System.out.println("thenRunAsync+e:\t"+Thread.currentThread()), e);
    e.shutdown();
}
Run Code Online (Sandbox Code Playgroud)

将打印

thenRun:        Thread[main,5,main]
thenRunAsync:   Thread[ForkJoinPool.commonPool-worker-1,5,main]
thenRunAsync+e: Thread[sole thread,5,main]
Run Code Online (Sandbox Code Playgroud)

public static void main(String[] args) {
   ExecutorService e=Executors.newSingleThreadExecutor(r -> new Thread(r, "sole thread"));
   CompletableFuture<?>f=CompletableFuture.runAsync(()->LockSupport.parkNanos((int)1e9),e);
   f.thenRun(()->System.out.println("thenRun:\t"+Thread.currentThread()));
   f.thenRunAsync(()->System.out.println("thenRunAsync:\t"+Thread.currentThread()));
   f.thenRunAsync(()->System.out.println("thenRunAsync+e:\t"+Thread.currentThread()), e);
   LockSupport.parkNanos((int)2e9);
   e.shutdown();
}
Run Code Online (Sandbox Code Playgroud)

将打印

thenRun:        Thread[sole thread,5,main]
thenRunAsync:   Thread[ForkJoinPool.commonPool-worker-1,5,main]
thenRunAsync+e: Thread[sole thread,5,main]
Run Code Online (Sandbox Code Playgroud)

因此thenRun可以在调用者的线程或者线程中执行操作,Executor而单参数thenRunAsync将始终使用Fork/Join池,并且只有两个参数thenRunAsync将始终使用提供的执行器.

  • @kantianethics,使用该术语“完成方法”而不对其进行定义是文档的一个缺陷,但是如该答案的代码示例所示,`thenRun` *是这样的一种完成方法。实际上,这些用于链接从属动作的方法中的任何一种都是一种完成方法,它可以执行从属动作,而不仅限于您正在链接的动作。换句话说,如果线程A同时链接动作* a *,线程B链接动作* b *,则甚至有可能A执行* b *,而B执行* a *。这些没有“…异步”的方法提供的控制最少。 (2认同)