CompletableFuture的实例无法获得预期的结果 [英] instance of CompletableFuture cannot get expected result

查看:177
本文介绍了CompletableFuture的实例无法获得预期的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

    CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("enter into completableFuture()");
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("start to out of completableFuture()");
        return "a";
    });

    System.out.println("do something else");

    cf1.thenApply(v -> v + " b").thenAcceptAsync(v ->
            System.out.println(v)
    );

    System.out.println("finalize...");

    //cannot get expected result, if this line was comment out.
    //TimeUnit.SECONDS.sleep(10);

上面的代码。

写作时在jdk8中使用CompletableFuture的一个例子,我感到困惑。

when writing a example of using CompletableFuture in jdk8, I got confused.

我必须添加最后一行

TimeUnit.SECONDS.sleep(10);

以获得预期结果。

如果我不让它的主线程进入休眠状态,我想知道程序是否已经结束。如果没有,为什么我不能得到输出?

I would like to know whether the program has ended if I do not let its main thread to sleep. if not, why I cannot get the output?

非常感谢你的时间。

推荐答案

当没有非守护程序线程正在运行时,JVM终止,因此如果异步操作仅由守护程序线程执行,它将在主线程终止时终止,而不是继续后台操作。

A JVM terminates when no non-daemon threads are running, so if asynchronous operations are executed by daemon threads only, it will terminate when the main thread terminates, not continuing the background operations.

有几种方法可以解决这个问题。

There are several ways to solve this.


  1. 如果后台计算形成一个依赖项您可以使用最后一个操作来等待其完成,因为它的完成意味着所有先前阶段的完成。让主线程等到完成将JVM的终止推迟到该点:

  1. If the background computations form a single dependency chain, you can use the last operation to wait for its completion, as its completion implies the completion of all previous stages. Letting the main thread wait until the completion defers the JVM’s termination to that point:

CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("enter into completableFuture()");
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    System.out.println("start to out of completableFuture()");
    return "a";
});
System.out.println("do something else");
CompletableFuture last
    = cf1.thenApply(v -> v + " b").thenAcceptAsync(System.out::println);
System.out.println("finalize...");
last.join();


  • 考虑 CompletableFuture 的文档:


    使用 async 方法。 com / javase / 8 / docs / api / java / util / concurrent / ForkJoinPool.html#commonPool--rel =nofollow noreferrer> ForkJoinPool.commonPool()(除非它不支持并行级别至少有两个,在这种情况下,创建一个新线程来运行每个任务。)

    All async methods without an explicit Executor argument are performed using the ForkJoinPool.commonPool() (unless it does not support a parallelism level of at least two, in which case, a new Thread is created to run each task).

    因为它是F / F的属性J公共池使用守护程序线程,在这种情况下我们可以使用该知识等待所有待处理任务的完成,这与这些待处理任务之间的依赖关系无关:

    Since it’s the property of that F/J common pool to use daemon threads, we can use that knowledge to wait for the completion of all pending tasks in that case, which works independently of the dependencies between these pending tasks:

    CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("enter into completableFuture()");
        LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
        System.out.println("start to out of completableFuture()");
        return "a";
    });
    System.out.println("do something else");
    cf1.thenApply(v -> v + " b").thenAcceptAsync(System.out::println);
    System.out.println("finalize...");
    if(ForkJoinPool.getCommonPoolParallelism()>1)
        ForkJoinPool.commonPool().awaitQuiescence(1, TimeUnit.DAYS);
    


  • 使用显式执行程序,它不会使用守护程序线程。 JRE提供的线程池执行器,允许 ForkJoinPool ,默认情况下使用非守护进程线程:

  • Use an explicit executor, which will not use daemon threads. The thread pool executors provided by the JRE, letting ForkJoinPool aside, use non-daemon threads by default:

    final ExecutorService threadPool = Executors.newCachedThreadPool();
    CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("enter into completableFuture()");
        LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
        System.out.println("start to out of completableFuture()");
        return "a";
    }, threadPool);
    System.out.println("do something else");
    cf1.thenApply(v -> v + " b").thenAcceptAsync(System.out::println);
    System.out.println("finalize...");
    threadPool.shutdown();
    

    请注意 threadPool.shutdown(); 并不意味着等待,也不会停止等待任务;它只会停止接受新任务,并确保在处理完所有待处理任务后池池线程将终止。您可以在使用 supplyAsync 之后直接放置它,而不会改变行为。

    Note that threadPool.shutdown(); does not imply waiting nor does it stop pending tasks; it only stops accepting new tasks and ensures that the pooled threads will terminate once all pending tasks have been processed. You could place it directly after using it with supplyAsync, without changing the behavior.

    所以第三个解决方案是只有一个允许 main 线程退出,JVM继续,直到处理完所有挂起的后台任务,因为它们在非守护程序线程中运行。

    So the third solution is the only one letting the main thread exit, with the JVM continuing until all pending background tasks are processed, as they are running in non-daemon threads.

    这篇关于CompletableFuture的实例无法获得预期的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆