CompletableFuture 和 thenAccept lambda 函数不在主线程中执行

问题描述

在 Java 中使用 CompletableFuture,我意识到在 CompletableFuture 上使用 thenAccept 或其他同步方法非常棘手,如本网站所述:https://mobiarch.wordpress.com/2018/09/07/understanding-java-completablefuture/。我逐字引用:

对于像 thenAccept 这样的非异步方法,事情并不那么简单。 Java 使用此策略: 如果调用 thenAccept() 的未来在调用之前已经完成,那么 lambda 将在调用 thenAccept() 的同一线程中调用。 如果调用 thenAccept() 时未完成尚未完成,则将在完成未完成的同一线程中调用 lambda。在我们的例子中,这将是来自认 ForkJoinPool 的线程”。 基本上非异步方法试图避免任何不必要的线程切换。这具有更少的 cpu 开销并且运行速度更快。但是如果 lambda 需要很长时间才能完成,我们就有阻塞主线程的风险。

我认为这是一个非常意外的行为,没有很好的文档记录和棘手,因为我创建了一些 CompletableFuture 来运行一个异步任务,以便从中返回一些东西,然后使用 thenAccept 等待该任务完成,并使用 lambda 函数获取结果返回给客户端。但是 lambda 函数没有在主线程中执行,导致向客户端返回了一些认值,而不是计算出来的值。

  • 这是因为我使用了 lambda 函数

  • 为什么这这么棘手?

  • 导致这种行为的是 JRE 而不是代码本身?

谢谢

解决方法

答案很简单,而且已经讨论了很多here

如果您希望确定性在哪个线程中执行您的操作,请使用 thenApplyAsync/thenAcceptAsync/etc 版本。