CompletableFuture允许为异步调用提供回调。您可以创建一长串回调,其中每个异步调用都会在完成时触发下一个回调。这被认为是编写异步代码的一种更好的方法,而不是使用Future,因为您在触发下一个之前,必须阻塞线程以获取第一次计算的结果。
我可以理解以下观点,即Completable Futures中的回调链可以提供更具可读性的代码,但我想知道这种方法是否还具有性能优势?还是仅仅是语法糖?
例如,考虑以下代码:
ExecutorService exec = Executors.newSingleThreadExecutor();
CompletableFuture.supplyAsync(this::findAccountNumber, exec)
.thenApply(this::calculateBalance)
.thenApply(this::notifyBalance)
.thenAccept((i)->notifyByEmail())
.join();
在这段代码中,calculateBalance()
直到findAccountNumber()
完成才开始,因此calculateBalance()
在findAccountNumber()
上被阻塞,以此类推,在回调链中的下一个方法如此。它比以下(性能方面)更好吗?
ExecutorService exec = Executors.newSingleThreadExecutor();
Future<Integer> accountNumberFuture = exec.submit(findAccountNumberCallable);
Integer accountNumber = accountNumberFuture.get();
Future<String> calculateBalanceFuture = exec.submit(calculateBalanceCallable(accountNumber);
....
....
答案 0 :(得分:0)
在大多数情况下,您不会注意到有什么不同,但是如果您希望能够有很多并发的异步调用等待某事,则可以使用CompletableFuture
。
原因是,如果仅在常规get()
上调用Future
,则Thread
会阻塞与之关联的所有资源,直到调用返回。如果调用次数很多,则线程池可能会用尽,或者如果使用CachedThreadPool
,则可能会导致创建很多线程。
使用CompletableFuture
,将一个对象存储在堆上,该对象表示应用程序接下来应从何处开始,而不是使用调用堆栈。构建API的人通过here进行了讨论。