有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java CompletableFuture未按预期工作

我试图从Java8理解CompletableFuture的工作原理。下面的代码按预期工作

CompletableFuture.supplyAsync(() -> {
    System.out.println("supplyAsync Thread name " + Thread.currentThread().getName());
    return "str";
}).thenApply(str -> {
    System.out.println("thenApply Thread name " + Thread.currentThread().getName());
    return str;
}).thenApply(str1 -> {
    System.out.println("thenApply Thread name " + Thread.currentThread().getName());
    return str1;
}).thenAccept(str3 -> {
    System.out.println("thenAccept Thread name " + Thread.currentThread().getName());
});
System.out.println("Thread name " + Thread.currentThread().getName());

输出:

supplyAsync Thread name ForkJoinPool.commonPool-worker-1
thenApply Thread name main
thenApply Thread name main
thenAccept Thread name main
Thread name main

但是当我进行一些计算时,它并没有像预期的那样工作。如果我遗漏了什么,请纠正我

CompletableFuture.supplyAsync(() -> {
    System.out.println("supplyAsync Thread name " + Thread.currentThread().getName());
    long val = 0;
    for (long i = 0; i < 1000000; i++) {
        val++;
    }
    return "str";
}).thenApply(str -> {
    System.out.println("thenApply Thread name " + Thread.currentThread().getName());
    long val = 0;
    for (long i = 0; i < 1000000; i++) {
        val++;
    }
    return str;
}).thenApply(str1 -> {
    System.out.println("thenApply Thread name " + Thread.currentThread().getName());
    long val = 0;
    for (long i = 0; i < 1000000; i++) {
        val++;
    }
    return str1;
}).thenAccept(str3 -> {
    System.out.println("thenAccept Thread name " + Thread.currentThread().getName());
    long val = 0;
    for (long i = 0; i < 1000000; i++) {
        val++;
    }
});

System.out.println("Thread name " + Thread.currentThread().getName());

输出为:

supplyAsync Thread name ForkJoinPool.commonPool-worker-1
Thread name main

我同意我没有将子线程连接到主线程。我的理解是子线程应该独立于主线程打印语句。问题是为什么它根本不打印


共 (2) 个答案

  1. # 1 楼答案

    解释

    您没有将子线程ForkJoinPool.commonPool-worker-1连接到主线程。所以一旦线程main完成,它就会被杀死

    解决方案

    在代码中的某个时刻,尝试调用.join()来描述你的完全未来。请注意,此方法正在阻止main线程。因此,连接点之后的执行将暂停,直到子线程完成其执行

    CompletableFuture.supplyAsync(() -> {
        System.out.println("=> supplyAsync Thread name " + Thread.currentThread().getName());
        // ...
    }).thenApply(str -> {
        System.out.println("thenApply Thread name " + Thread.currentThread().getName());
        // ...
    }).thenApply(str1 -> {
        System.out.println("thenApply Thread name " + Thread.currentThread().getName());
        // ...
    }).thenAccept(str3 -> {
        System.out.println("thenAccept Thread name " + Thread.currentThread().getName());
        // ...
    }).join()
    

    将打印:

    supplyAsync Thread name ForkJoinPool.commonPool-worker-1
    thenApply Thread name ForkJoinPool.commonPool-worker-1
    thenApply Thread name ForkJoinPool.commonPool-worker-1
    thenAccept Thread name ForkJoinPool.commonPool-worker-1
    Thread name main
    

    如果希望最后一个System.out.println(...)不依赖于子线程的执行,则将CompletableFuture分配给一个变量,并将其连接到main的最末端:

    CompletableFuture<Void> future = CompletableFuture.supplyAsync(...) ... // 
    
    System.out.println("Thread name " + Thread.currentThread().getName());
    
    future.join();    
    
  2. # 2 楼答案

    My understanding is child thread should print the statements independently of main thread.

    你的理解是错误的

    the documentation

    Actions supplied for dependent completions of non-async methods may be performed by the thread that completes the current CompletableFuture, or by any other caller of a completion method.

    这并不要求依赖完成由完成异步操作的线程执行,它只允许它

    不过,我同意另一个答案,即你应该安排在计算链完成之前不要退出主例程