CompletableFuture何时将线程释放回ThreadPool?是在调用get()方法之后还是在完成相关任务之后?

最佳答案

get调用与池中的线程之间没有关系。未来的完成状况和线索之间甚至没有任何关系。
CompletableFuture可以在任何地方完成,例如通过在其上调用complete。当您使用一种便利的方法将任务调度到最终将尝试完成的执行程序时,则在完成尝试时,线程将一直使用到这一点,而不管将来是否已经完成或不。
例如,

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()join()
即使您提前完成了未来,例如通过complete("some other string")或通过cancel(…),它对正在进行的计算没有影响,因为没有从将来到作业的引用。作为the documentation of cancel states

参数:
mayInterruptIfRunning-此值在此实现中无效,因为不使用中断来控制处理。

根据上面的解释,应该清楚为什么。
创建依赖关系链时,例如通过b = a.thenApply(function)function完成之前,将不会提交将评估a的作业。 a完成时,将在b评估开始之前重新检查function的完成状态。如果此时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

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

关于java - Completable Future何时将线程释放回线程池?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48213670/

10-14 10:41