这两种方法之间的区别

时间:2019-08-14 19:31:40

标签: java java-8 completable-future

我无法发现这两种方法的行为为何不同。两者之间的唯一区别是sleep方法调用。

在第一种方法中,我期望第二个将来的执行将等待第一个将来完成,因为它取决于第一个的结果。

请帮助我理解为什么两种方法的行为都不同,或者我的代码在逻辑上有什么错误吗?

我尝试在调试模式下运行,但仍然给出了相同的结果。

public static void thenComposeWithSleep() {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "Hello";
        }).thenCompose(value -> CompletableFuture.supplyAsync(() -> value + " Then compose is been called"));
        completableFuture.thenAccept(System.out::println);
    }

public static void thenCompose() {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello")
                .thenCompose(value -> CompletableFuture.supplyAsync(() -> value + " Then compose is been called"));
        completableFuture.thenAccept(System.out::println);
    }

第一种方法的预期输出:“您好,然后调用了compose。”

第一种方法的实际输出:空字符串

第二种方法的预期和实际输出相同。

输出:“您好,然后调用了compose”

1 个答案:

答案 0 :(得分:3)

这里的问题是

CompletableFuture.supplyAsync()

将执行移交给

ForkJoinPool.commonPool()

当它在守护程序模式下运行时(根据Java7文档,这是默认设置),如果您的主线程终止,则所有未完成的异步任务都将被丢弃并且永远不会完成。

所以我的猜测是您假设的“空字符串”实际上是

System.out::println

根本没有执行。

在课堂上对此进行说明

public class DaemonsAtPlay {

    public static void thenComposeWithSleep() {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            return "Slept"; //HERE
        }).thenCompose(value -> CompletableFuture.supplyAsync(() -> value + " Then compose is been called"));
        completableFuture.thenAccept(DaemonsAtPlay::report); //HERE
    }

    public static void thenCompose() {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello")
                .thenCompose(value -> CompletableFuture.supplyAsync(() -> value + " Then compose is been called"));
        completableFuture.thenAccept(DaemonsAtPlay::report); //HERE
    }

    private static final AtomicInteger counter = new AtomicInteger();

    static void report(String msg) {
        System.out.println("report: " + counter.incrementAndGet() + "; message: >" + msg + "<");
    }

    public static void executeMultiple(int iterations, boolean withsleep) {
        for(int i=0; i<iterations; ++i) {
            if(withsleep) {
                thenComposeWithSleep();
            } else {
                thenCompose();
            }
        }
    }

    public static void main(String... none) throws Exception {
        executeMultiple(100, false);
        executeMultiple(100, true);
        report("exiting main");
    }
}

我得到了输出

report: 1; message: >Hello Then compose is been called<
report: 2; message: >Hello Then compose is been called<
report: 3; message: >Hello Then compose is been called<
report: 4; message: >Hello Then compose is been called<
report: 5; message: >Hello Then compose is been called<
report: 6; message: >Hello Then compose is been called<
report: 7; message: >Hello Then compose is been called<
report: 8; message: >Hello Then compose is been called<
report: 9; message: >Hello Then compose is been called<
report: 10; message: >Hello Then compose is been called<
report: 11; message: >Hello Then compose is been called<
report: 12; message: >Hello Then compose is been called<
report: 13; message: >Hello Then compose is been called<
report: 14; message: >Hello Then compose is been called<
report: 15; message: >Hello Then compose is been called<
report: 16; message: >Hello Then compose is been called<
report: 17; message: >Hello Then compose is been called<
report: 18; message: >Hello Then compose is been called<
report: 19; message: >Hello Then compose is been called<
report: 20; message: >Hello Then compose is been called<
report: 21; message: >Hello Then compose is been called<
report: 22; message: >exiting main<

哪个说明了不仅“睡眠”任务而且许多“睡眠”任务都没有终止。

如果要等待所有CompletableFuture任务终止,可以使用

CompletableFuture.join()

在主线程上。

相关问题