您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

CompletableFuture的完成处理程序在哪个线程中执行?

CompletableFuture的完成处理程序在哪个线程中执行?

CompletableFuture文档中指定的策略可以帮助您更好地理解:

对于非异步方法依赖完井供给动作可以由执行 该完成当前CompletableFuture线程或者通过完成方法的任何其他呼叫者

所有没有显式Executor参数的异步方法都使用来执行ForkJoinPool.commonPool()(除非它不支持并行度至少为2,在这种情况下,将创建一个新的Thread来运行每个任务 )。为了简化监视,调试和跟踪,所有生成的异步任务都是标记接口的实例CompletableFuture.AsynchronousCompletionTask

:我也建议阅读@Mike的答案,作为对文档详细信息的有趣分析。

正如@nullpointer指出的那样,文档会告诉您您需要了解的内容。但是,相关文本令人惊讶地模糊不清,此处发布的某些评论(和答案)似乎依赖于文档不支持的假设。因此,我认为有必要将其分开。具体来说,我们应该非常仔细地阅读本段内容

为非异步方法的相关完成提供的动作可以由完成当前CompletableFuture的线程执行,也可以由完成方法的任何其他调用者执行。

听起来很简单,但是细节上却很少。似乎故意避免描述何时可以在完成线程上调用依赖完成,而不是在调用诸如的完成方法期间thenApply。如前所述,以上段落实际上是在恳求我们用假设来填补空白。这很危险,特别是当主题涉及并发和异步编程时,当我们随着程序员的发展而产生的许多期望被抛诸脑后。让我们仔细看一下文档中没有说的内容

该文档没有声称在调用之前注册的相关完成complete()将在完成线程上运行。而且,尽管它声明在调用诸如的完成方法时可能会调用从属补全thenApply,但并未声明将在注册它的线程上调用补全(注意单词“ any other”)。

对于任何CompletableFuture用于计划和撰写任务的人来说,这些都是潜在的重要点。考虑以下事件序列:

从概念上讲,complete()它做两件事:发布将来的结果,然后尝试调用相关的完成。现在,如果线程C 在发布结果值之后但在线程B开始调用之前运行,该c1怎么办?根据实现的不同,线程C可能会看到f已经完成,然后可以调用c1 和 c2。或者,线程C可以调用,c2而线程B可以调用c1。该文档不排除任何可能性。考虑到这一点,以下是文档不支持的假设:

考虑另一个示例:

如果知道f已经完成,可以尝试假设c1会在期间调用f.thenApply(c1)和c2会在期间调用f.thenApply(c2)。人们可能会进一步假设,c1到时间f.thenApply(c1)返回时,它已经完成了。但是,文档不支持这些假设。它可能是一个线程,呼吁thenApply各上调调用既 c1和c2,而其他线程调用都不是。

仔细分析JDK代码可以确定上面的假设方案如何发挥作用。但这甚至是有风险的,因为您最终可能会依赖于(1)不可移植或(2)可能会更改的实现细节。最好的选择是不要假设javadocs或原始JSR规范中未阐明的任何内容

tldr:谨慎假设,编写文档时,请尽可能清晰明了。简洁是一件奇妙的事情,但请注意人类填补空白的趋势。

其他 2022/1/1 18:14:11 有556人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶