Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring boot@Async方法实际上是如何异步/非阻塞的?_Java_Spring_Spring Boot_Completable Future_Spring Async - Fatal编程技术网

Java Spring boot@Async方法实际上是如何异步/非阻塞的?

Java Spring boot@Async方法实际上是如何异步/非阻塞的?,java,spring,spring-boot,completable-future,spring-async,Java,Spring,Spring Boot,Completable Future,Spring Async,以下示例取自 这实际上会阻塞它将阻止Executor服务上的另一个线程,但它将由于线程而被阻止。sleep(1000L)正确吗? 那么这是如何异步的呢 我的意思是,CompletableFuture的全部要点是获取对未来将完成的计算的引用但是在这里,当我得到完整的未来时,计算已经结束了,即,我们正在使用CompletableFuture.completedFuture(结果) 那么,在这种情况下,拥有一个完整的未来有什么意义呢我的意思是,如果我只在计算结束并得到结果时才阻塞并返回,那么我最好只返

以下示例取自

这实际上会阻塞它将阻止
Executor
服务上的另一个线程,但它将由于
线程而被阻止。sleep(1000L)
正确吗?

那么这是如何异步的呢

我的意思是,
CompletableFuture
的全部要点是获取对未来将完成的计算的引用但是在这里,当我得到完整的未来时,计算已经结束了,即,我们正在使用
CompletableFuture.completedFuture(结果)

那么,在这种情况下,拥有一个完整的未来有什么意义呢我的意思是,如果我只在计算结束并得到结果时才阻塞并返回,那么我最好只返回结果,而不是
CompletableFuture

这是如何真正实现非阻塞/异步的

我在这里发现的唯一一个非阻塞方面是卸载到另一个线程,而不是别的。

我哪里出了问题吗?我错过了什么


谢谢。

问题在于你如何创造你的
未来。您使用的代码是

CompletableFuture.completedFuture(results)
引用,这只是同步和异步之间的包装,其中计算是同步完成的:

返回已使用给定值完成的新CompletableFuture

这在某些情况下非常有用,因为您只希望对某些输入执行异步工作。考虑

(x) -> x==0 ? CompletableFuture.completedFuture(0) : CompletableFuture.supplyAsync(expensiveComputation)
我希望这能让区别变得清晰-如果您想要真正的异步计算,您需要使用
supplyAsync
函数:

返回一个新的
CompletableFuture
,该任务由运行在
ForkJoinPool.commonPool()
中的任务异步完成,其值通过调用给定的
供应商获得


您缺少的细节是,当使用
@Async
时(并正确配置),将使用代理bean包装您的服务bean。通过代理对异步方法的任何调用都将使用Spring异步运行该方法

将方法响应包装在一个同步的
Future
中,例如
CompletableFuture。completedFuture
是必需的,因此返回类型可以是
Future
。但是,您返回的
Future
不是代理返回的。相反,代理返回由
TaskExecutor
提供的
Future
,它将被异步处理。您通过创建的
Future
,例如
CompletableFuture.completedFuture
由代理展开,其完成结果由代理的
Future
返回

代理文档 我没有看到在或或Javadocs中明确说明的所有上述代理细节。但是,可以通过阅读所提供内容的字里行间来拼凑细节

@Async
Javadocs顺便提到了服务代理,并解释了在服务方法的实现中使用
CompletableFuture.completedFuture
的原因:

从代理返回的
Future
句柄将是一个实际的异步
Future
,可用于跟踪异步方法执行的结果。但是,由于目标方法需要实现相同的签名,因此它必须返回一个临时的
Future
句柄,该句柄只传递一个值:例如Spring的
AsyncResult
、EJB3.1的
AsyncResult
、或
CompletableFuture.completedFuture(对象)

代理涉及的事实也很明显,因为两个
@EnableAsync
注释元素指定代理细节:和

问题示例 最后,将此应用于问题示例将使其具体化。在GitHubLookupServicebean上调用findUser方法的代码实际上是在代理类上调用方法,而不是直接在GitHubLookupService实例上调用方法。代理类的
findUser
方法将任务提交给Spring的
TaskExecutor
,并返回一个
CompletableFuture
,该任务将在提交的任务完成时异步完成

提交的任务将调用非代理
GitHubLookupService
中的实际
findUser
方法。这将执行REST调用,休眠1秒,并返回一个完整的
CompletableFuture
,其中包含REST结果

由于此任务发生在Spring的
TaskExecutor
创建的单独线程中,因此调用代码将继续立即通过
GitHubLookupService.findUser
调用,即使它至少需要1秒才能返回


如果调用代码中使用了
findUser
调用的结果(例如使用),则从
Future
中获得的值将与
results
中传递给
CompletableFuture.completedFuture
值相同。

我没有在这里编写代码。我是从Spring文档中得到的。这是不准确的,因为Spring代理魔法正在幕后进行:。在这个问题中使用的
CompletableFuture.completedFuture(results)
是惯用的Spring
@Async
方法,最终结果仍然是一个异步调用。
CompletableFuture.completedFuture(results)
(x) -> x==0 ? CompletableFuture.completedFuture(0) : CompletableFuture.supplyAsync(expensiveComputation)