Completable Future发布什么时候会回线到线程池?

sre*_*ath 2 java threadpool java-8 completable-future

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

Hol*_*ger 5

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

A CompletableFuture可以从任何地方完成,例如通过呼叫complete它.当您使用其中一种便捷方法将任务计划到最终将尝试完成它的执行程序时,无论将来是否已完成,或者在完成尝试时,该线程将被用于该点.不.

例如,

CompletableFuture<String> f = CompletableFuture.supplyAsync(() -> "hello");
Run Code Online (Sandbox Code Playgroud)

在语义上等同于

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

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

很明显,线程池和预定的操作都不关心某人是否调用get()join()未来.

即使您提前完成未来,例如通过complete("some other string")或通过cancel(…),它也不会影响正在进行的计算,因为未来没有对工作的参考.由于的文件cancel状态:

参数:

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

鉴于上述解释,应该清楚为什么.

创建依赖关系链时存在差异,例如通过b = a.thenApply(function).评估的工作将functiona完成之前提交.到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);
Run Code Online (Sandbox Code Playgroud)

只会打印

faster
Run Code Online (Sandbox Code Playgroud)

但是一旦评估开始,它就无法停止

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);
Run Code Online (Sandbox Code Playgroud)

将打印

starting to evaluate foo
faster
finishing to evaluate foo
Run Code Online (Sandbox Code Playgroud)

表明即使您成功从早期完成的未来中检索到值,也可能会有一个仍在运行的后台计算,它将尝试完成未来.但随后的完成尝试将被忽略.