如果在 runAsync 调用之后链接,thenRunAsync(相对于 thenRun)是否有任何区别?
Does thenRunAsync (as opposed to thenRun) make any difference if chained after a runAsync call?
在下面的代码中,调用 thenRunAsync 有什么不同吗?我应该只调用 thenRun 吗?
CompletableFuture.runAsync(this::doWork , executorService)
.thenRunAsync(this::handleSuccess);
针对评论的详细说明:如果我改用此代码,
CompletableFuture.runAsync(this::doWork , executorService)
.thenRun(this::handleSuccess);
它的行为会有什么不同吗?
在这两种情况下,行为都是非阻塞的,第二个任务不会 运行 直到第一个任务完成,据我所知,无论如何。
如果 CompletableFuture
已经完成,方法 thenRun
允许直接在调用者的线程中执行 Runnable
。因为即使在像 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();
}
将打印
thenRun: Thread[main,5,main]
thenRunAsync: Thread[ForkJoinPool.commonPool-worker-1,5,main]
thenRunAsync+e: Thread[sole thread,5,main]
而
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();
}
将打印
thenRun: Thread[sole thread,5,main]
thenRunAsync: Thread[ForkJoinPool.commonPool-worker-1,5,main]
thenRunAsync+e: Thread[sole thread,5,main]
所以 thenRun
可以在调用者的线程或 Executor
的线程中执行操作,而单参数 thenRunAsync
将始终使用 Fork/Join pool 和只有两个参数 thenRunAsync
将始终使用提供的执行程序。
在下面的代码中,调用 thenRunAsync 有什么不同吗?我应该只调用 thenRun 吗?
CompletableFuture.runAsync(this::doWork , executorService)
.thenRunAsync(this::handleSuccess);
针对评论的详细说明:如果我改用此代码,
CompletableFuture.runAsync(this::doWork , executorService)
.thenRun(this::handleSuccess);
它的行为会有什么不同吗?
在这两种情况下,行为都是非阻塞的,第二个任务不会 运行 直到第一个任务完成,据我所知,无论如何。
如果 CompletableFuture
已经完成,方法 thenRun
允许直接在调用者的线程中执行 Runnable
。因为即使在像 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();
}
将打印
thenRun: Thread[main,5,main]
thenRunAsync: Thread[ForkJoinPool.commonPool-worker-1,5,main]
thenRunAsync+e: Thread[sole thread,5,main]
而
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();
}
将打印
thenRun: Thread[sole thread,5,main]
thenRunAsync: Thread[ForkJoinPool.commonPool-worker-1,5,main]
thenRunAsync+e: Thread[sole thread,5,main]
所以 thenRun
可以在调用者的线程或 Executor
的线程中执行操作,而单参数 thenRunAsync
将始终使用 Fork/Join pool 和只有两个参数 thenRunAsync
将始终使用提供的执行程序。