更好的 CompletableFuture 方法 acceptEither 与 acceptEitherAsync 有什么区别?

问题描述 投票:0回答:1

例如-

CompletableFuture.supplyAsync(stage1).acceptEither(stage2, consumer );

stage1 和 stage2 应该在上面的代码中并行运行,因为它使用了

acceptEither

如果我更改为

acceptEitherAsync
,我发现我可以更好地控制哪个线程(来自 ForkJoin 池的线程或来自自定义执行程序池的线程)运行 stage2.

但是在运行下面的代码时(jdoddle 链接)我发现stage2

is not running in 
main` 线程但是在 ForkJoin 池中。这怎么可能。 来自Java Doc -

为非异步方法的依赖完成提供的操作可能是 由完成当前 CompletableFuture 的线程执行, 或任何其他完成方法的调用者。

import java.util.concurrent.CompletableFuture;

public class MyClass {
    public static void main(String args[]) {
                System.out.println("hello world, CompletableFuturesRightHere");

     CompletableFuture.supplyAsync(() -> {
            System.out.println("log-sA: " + Thread.currentThread().getName());
            System.out.println("log-sA post: " + Thread.currentThread().getName());
            return 40;
        }).acceptEither(CompletableFuture.supplyAsync(() -> {
            System.out.println("log-aE: " + Thread.currentThread().getName());
            System.out.println("log-aE post: " + Thread.currentThread().getName());
            return 80;
        }), a -> { System.out.println(a); } );
  }
}

输出:

hello world, CompletableFuturesRightHere
log-aE: ForkJoinPool.commonPool-worker-5
log-sA: ForkJoinPool.commonPool-worker-3
log-aE post: ForkJoinPool.commonPool-worker-5
log-sA post: ForkJoinPool.commonPool-worker-3
40

stage2log-aE 如何在 worker-5 中运行,它应该在 main 或 worker-3 中运行。但是由于 stage1 和 stage2 应该并行运行,而 worker-3 已经在运行 stage1,所以留给 stage2 的唯一线程是

main
stage2 怎么能在 worker-5 中运行。

java multithreading java.util.concurrent completable-future
1个回答
3
投票

如果您不在线执行所有操作,这可能会更清楚。例如:

// You used 'supplyAsync', which means the 'Supplier' will be executed
// using the common ForkJoinPool (any available thread from that pool)
CompletableFuture<Integer> stage1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("Stage 1: " + Thread.currentThread().getName());
    return 40;
});

// You used 'supplyAsync' *again*, which means the 'Supplier' will be executed
// using the common ForkJoinPool (any available thread from that pool)
CompletableFuture<Integer> stage2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("Stage 2: " + Thread.currentThread().getName());
    return 80;
});

/*
 * Both 'stage1' and 'stage2' have been set to execute using the common
 * ForkJoinPool. The use of 'acceptEither', or even 'acceptEitherAsync',
 * has no bearing on that. Because you used 'acceptEither', the
 * **CONSUMER** will be executed by the same thread which finished 'stage1'
 * or the same thread that finished 'stage2', whichever happens first,
 * or the caller thread (typically if 'stage1' and/or 'stage2' are already
 * complete by the time 'acceptEither' is invoked).
 */
stage1.acceptEither(stage2, result -> {
    System.out.println("Stage acceptEither: " + Thread.currentThread().getName());
    System.out.println("Result = " + result);
});

注意:

supplyAsync
有一个重载接受一个
Executor
,允许你指定一个不同于普通
ForkJoinPool
的线程池。所有
xxxAsync
方法也是如此。

© www.soinside.com 2019 - 2024. All rights reserved.