Java 使用带有CompletableFuture的默认公共fork/join池进行长阻塞调用是否是一种错误的做法?
假设我有一个CompletableFuture,它封装了一个阻塞调用,就像使用JDBC查询后端一样。在这种情况下,由于我没有将任何executor服务作为参数传递给CompletableFuture.SupplySync(),因此通过后端获取资源的实际阻塞工作应该由公共分叉/联接池中的线程完成让来自普通FJpool的线程执行阻塞调用不是很好吗?我在这里的优势是我的主线程没有阻塞,因为我将阻塞调用委托给异步运行。检查abt JDBC调用是否被阻塞。如果这个推论是正确的,为什么我们可以选择使用默认的通用FJpool和CompletableFutureJava 使用带有CompletableFuture的默认公共fork/join池进行长阻塞调用是否是一种错误的做法?,java,asynchronous,java-8,completable-future,Java,Asynchronous,Java 8,Completable Future,假设我有一个CompletableFuture,它封装了一个阻塞调用,就像使用JDBC查询后端一样。在这种情况下,由于我没有将任何executor服务作为参数传递给CompletableFuture.SupplySync(),因此通过后端获取资源的实际阻塞工作应该由公共分叉/联接池中的线程完成让来自普通FJpool的线程执行阻塞调用不是很好吗?我在这里的优势是我的主线程没有阻塞,因为我将阻塞调用委托给异步运行。检查abt JDBC调用是否被阻塞。如果这个推论是正确的,为什么我们可以选择使用默认的
CompletableFuture<List<String>> fetchUnicorns =
CompletableFuture.supplyAsync(() -> {
return unicornService.getUnicorns();
});
fetchUnicorns.thenAccept(/**Do something with the result*/);
CompletableFuture fetchUnicorns=
CompletableFuture.SupplySync(()->{
返回unicornService.getUnicorns();
});
fetchUnicorns.thenAccept(/**对结果做点什么*/);
如果这个推论是正确的,为什么我们可以选择使用默认的通用FJpool和CompletableFuture
CompletableFuture<List<String>> fetchUnicorns =
CompletableFuture.supplyAsync(() -> {
return unicornService.getUnicorns();
});
fetchUnicorns.thenAccept(/**Do something with the result*/);
因为并不是所有的工作都是阻塞的
您可以选择在具有CompletableFuture.supplyAsync(供应商,执行者)的自定义执行器上安排阻塞工作。您不应该使用阻塞调用(以这种方式)的原因是,公共池并行性已配置为利用现有的CPU核心,假定为非阻塞作业。阻塞的线程将降低使用相同池的其他任务的并行性 但有一个官方的解决方案:
class BlockingGetUnicorns implements ForkJoinPool.ManagedBlocker {
List<String> unicorns;
public boolean block() {
unicorns = unicornService.getUnicorns();
return true;
}
public boolean isReleasable() { return false; }
}
CompletableFuture<List<String>> fetchUnicorns =
CompletableFuture.supplyAsync(() -> {
BlockingGetUnicorns getThem = new BlockingGetUnicorns();
try {
ForkJoinPool.managedBlock(getThem);
} catch (InterruptedException ex) {
throw new AssertionError();
}
return getThem.unicorns;
});
在这里。在生产环境中,您将保留对执行器的引用,重用它,并最终对其调用shutDown
。对于不重用执行器的用例
CompletableFuture<List<String>> fetchUnicorns =
CompletableFuture.supplyAsync(() -> unicornService.getUnicorns(),
r -> new Thread(r).start());
CompletableFuture fetchUnicorns=
CompletableFuture.SupplySync(()->unicornService.getUnicorns(),
r->新线程(r.start());
这样就足够了,线程将在作业完成后自动释放。
CompletableFuture
作为API有许多设计缺陷,这就是其中之一。是的,在任何线程池(包括FJ池)中混合阻塞和非阻塞任务都是不好的做法。感谢您提供有关ForkJoinPool.ManagedBlocker的信息。有帮助!这个答案真的很有帮助!谢谢