Chi*_*may 11 java asynchronous java-8 completable-future
假设我有一个CompletableFuture,它包含一个阻塞调用,比如使用JDBC查询后端.在这种情况下,由于我没有将任何执行程序服务作为参数传递给CompletableFuture.supplyAsync(),因此通过后端获取资源的实际阻塞工作应该由公共Fork/Join池中的线程完成.让来自普通FJpool的线程阻塞调用不是不好的做法吗?我在这里的优点是我的主线程没有阻塞,因为我委托阻塞调用异步运行.在这里检查abt JDBC调用是否阻塞.如果这个推论是正确的,为什么可以选择使用带有CompletableFuture的默认公共FJpool?
CompletableFuture<List<String>> fetchUnicorns =
CompletableFuture.supplyAsync(() -> {
return unicornService.getUnicorns();
});
fetchUnicorns.thenAccept(/**Do something with the result*/);
Run Code Online (Sandbox Code Playgroud)
您不应该使用阻塞调用(以这种方式)的原因是,公共池并行性已配置为使用现有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;
});
Run Code Online (Sandbox Code Playgroud)
ForkJoinPool.ManagedBlocker 是一个潜在阻塞操作的抽象,它允许Fork/Join池在识别出工作线程即将被阻塞时创建补偿线程.
很明显,它更容易使用
CompletableFuture<List<String>> fetchUnicorns =
CompletableFuture.supplyAsync(() -> unicornService.getUnicorns(),
Executors.newSingleThreadExecutor());
Run Code Online (Sandbox Code Playgroud)
这里.在生产环境中,您将保留对执行程序的引用,重用它并最终调用shutDown它.对于不重用执行程序的用例,
CompletableFuture<List<String>> fetchUnicorns =
CompletableFuture.supplyAsync(() -> unicornService.getUnicorns(),
r -> new Thread(r).start());
Run Code Online (Sandbox Code Playgroud)
就足够了,因为这样,线程将在作业完成后自动处理.
如果这个推论是正确的,为什么可以选择将默认的通用 FJpool 与 CompletableFuture 一起使用?
因为并非所有工作都是阻塞的。
您可以选择在自定义执行器上安排阻塞工作CompletableFuture.supplyAsync(Supplier<U>, Executor)
| 归档时间: |
|
| 查看次数: |
3320 次 |
| 最近记录: |