java - 这2种方法的区别

标签 java java-8 completable-future

我无法找出为什么这两种方法的行为不同。两者之间的唯一区别是 sleep 方法调用。

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

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

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

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);
    }

第一个方法的预期输出:“Hello,然后 compose 被调用”。

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

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

输出:“Hello,然后 compose 被调用”

最佳答案

这里的问题是

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<

这说明不仅“ sleep ”任务没有终止,许多“未 sleep ”任务也没有终止。

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

CompletableFuture.join()

在主线程上。

关于java - 这2种方法的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57500928/

相关文章:

java - 如何在 Java 8 中使用流将集合/数组转换为 JSONArray

java - CompletableFuture allof(..).join() 与 CompletableFuture.join()

java - 如何使用hibernate从数据库中检索数据?

java - 用于 I/O 超时的最佳异常类型是什么?

java - 设计决策 - Math.java 中单独的 RandomNumberGenerator Holder 类的用途/优势是什么?

java - 实现 Nashorn ClassFilter 等价物

java - Akka:询问时丢失了 `child.path.name` 的引用

java - 为什么 CompletableFuture allOf 方法会进行二分查找?

java - 如何使用 Netbean 的 GUI Builder 单独调整表列的大小?

java - 当 onCreate 中完成某些操作(不是声明或初始化)但 onClick 中未完成某些操作时,应用程序崩溃