当前位置: 首页 > 知识库问答 >
问题:

何时Completable Future releases线程将返回到线程池?

仲孙英才
2023-03-14

CompletableFuture释放线程回到Threadpool?是调用get()方法后还是关联任务完成后?

共有1个答案

苏伟志
2023-03-14

get调用和池中的线程之间没有关系。未来的完成和线程之间甚至没有关系。

一个CompletableFuture可以从任何地方完成,例如通过调用完成。当您使用一种方便的方法将任务调度到最终将尝试完成它的执行器时,线程将一直使用到完成尝试完成时,无论未来是否已经完成。

例如,

CompletableFuture<String> f = CompletableFuture.supplyAsync(() -> "hello");

在语义上等同于

CompletableFuture<String> f = new CompletableFuture<>();

ForkJoinPool.commonPool().execute(() -> {
    try {
        f.complete("hello");
    } catch(Throwable t) {
        f.completeExceptionally(t);
    }
});

很明显,线程池和计划的操作都不关心将来是否有人调用get()加入()

即使您提前完成未来,例如通过complete(“某些其他字符串”)或通过cancel(…),也不会影响正在进行的计算,因为没有从未来到作业的引用。正如cancel的文档所述:

MayInterruptFrunning-此值在此实现中无效,因为中断不用于控制处理。

鉴于上述解释,原因应该很清楚。

创建依赖链时存在差异,例如通过b=a.then应用(函数)。将评估函数的作业在完成a之前不会提交。到a完成时,将在函数的计算开始之前重新检查b的完成状态。如果此时已完成b,则可能会跳过计算。

CompletableFuture<String> a = CompletableFuture.supplyAsync(() -> {
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    return "foo";
});
CompletableFuture<String> b = a.thenApplyAsync(string -> {
    System.out.println("starting to evaluate "+string);
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
    System.out.println("finishing to evaluate "+string);
    return string.toUpperCase();
});
b.complete("faster");
System.out.println(b.join());
ForkJoinPool.commonPool().awaitQuiescence(1, TimeUnit.DAYS);

只需打印

faster

但一旦评估开始就无法停止了所以

CompletableFuture<String> a = CompletableFuture.supplyAsync(() -> {
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    return "foo";
});
CompletableFuture<String> b = a.thenApplyAsync(string -> {
    System.out.println("starting to evaluate "+string);
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
    System.out.println("finishing to evaluate "+string);
    return string.toUpperCase();
});
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
b.complete("faster");
System.out.println(b.join());
ForkJoinPool.commonPool().awaitQuiescence(1, TimeUnit.DAYS);

会打印

starting to evaluate foo
faster
finishing to evaluate foo

这表明,即使在您成功地从较早完成的未来检索到值时,仍可能有一个仍在运行的后台计算将尝试完成未来。但随后的完成尝试将被忽略。

 类似资料:
  • 我有一个方法: 当包括睡眠和锁时,我得到: 不过,如果我注释所有锁和,它会按照预期工作。我需要锁,因为我正在处理其他线程。完整的代码如下所示:https://godbolt.org/z/7erjrg,因为otput提供的信息不多,所以我很累

  • 问题内容: 我如何获得一个线程以将元组或我选择的任何值返回给Python中的父级? 问题答案: 我建议您在启动线程之前实例化Queue.Queue,并将其作为线程的args之一传递:在线程完成之前,它将结果作为参数接收到的队列中。父母可以或愿意。 队列通常是在Python中安排线程同步和通信的最佳方法:队列本质上是线程安全的消息传递工具,这是组织多任务的最佳方法!

  • 问题内容: 我做了这样的一个波纹管: 但是当我尝试通过getTemp使用temp时我得到0 我只想使用我在线程中所做的计算将其存储在某些变量中以备后用。 问题答案: 或者简单地添加 等待线程完成,然后再获得结果。 您的问题是您试图在计算结果之前获得结果。您应该等待线程完成后才能获得结果。这个答案也许不是最好的,但是是最简单的。由于其他人已经在使用Executors课程,所以我不想重复他们的答案。但

  • 问题内容: 我有一个方法。值在内部被更改,我想将其返回给该方法。有没有办法做到这一点? 问题答案: 可以使用局部最终变量数组。该变量必须是非基本类型,因此可以使用数组。你还需要同步两个线程,例如使用CountDownLatch: 你也可以这样使用an Executor和a Callable:

  • 问题内容: 我有一个如下的Java线程: 我大约有300个ID,每隔几秒钟-我启动线程以对每个ID进行呼叫。例如。 现在,我想从每个线程收集结果,并批量插入数据库,而不是每2秒进行300次数据库插入。 知道我该如何做到吗? 问题答案: 如果要在执行数据库更新之前收集所有结果,则可以使用该方法。如daveb建议的那样,如果您一次提交一项任务,则可以完成簿记工作。

  • 问题内容: 我的android类中有以下线程。我如何从线程中获取err的值??? 我希望该值是方法的返回值,但是对于我一生来说,我无法获得该值… 问题答案: 您可以通过两种方式实现这一目标。 在 糟糕的 方式。创建一个可变对象,如整数 列表 ,然后让Thread(可运行)写入列表。您可以在外部类/方法的列表中访问值。 使用而不是。一个可以返回值