当前位置: 首页 > 知识库问答 >
问题:

返回CompletableFuture,而不暴露执行器线程

齐嘉庆
2023-03-14

我在库中公开了一个方法,该方法返回一个CompletableFuture。该方法的计算发生在单线程执行器上,这是我的瓶颈,因此我不希望任何后续工作发生在同一个线程上

如果我使用返回“SupplySync”结果的简单方法,我将向调用者公开我宝贵的线程,调用者可能会添加同步操作(例如通过Accept),这可能会在该线程上花费一些CPU时间

复制如下:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CfPlayground {
    private ExecutorService preciousExecService = Executors.newFixedThreadPool(1);

    CfPlayground() {}

    private static void log(String msg) {
        System.out.println("[" + Thread.currentThread().getName() + "] " + msg);
    }

    CompletableFuture<String> asyncOp(String param) {
        return CompletableFuture.supplyAsync(() -> {
            log("In asyncOp");
            return "Hello " + param;
        }, preciousExecService);
    }

    void syncOp(String salutation) {
        log("In syncOp: " + salutation);
    }

    void run() {
        log("run");
        asyncOp("world").thenAccept(this::syncOp);
    }

    public static void main(String[] args) throws InterruptedException {
        CfPlayground compFuture = new CfPlayground();
        compFuture.run();
        Thread.sleep(500);
        compFuture.preciousExecService.shutdown();
    }
}

这确实打印出:

[main] run
[pool-1-thread-1] In asyncOp
[pool-1-thread-1] In syncOp: Hello world

我发现的一个解决方案是引入另一个执行器,并在返回CompletableFuture之前使用该执行器添加一个no-op thenApplyAsync

    CompletableFuture<String> asyncOp(String param) {
        return CompletableFuture.supplyAsync(() -> {
            log("In asyncOp");
            return "Hello " + param;
        }, preciousExecService).thenApplyAsync(s -> s, secondExecService);
    }

这行得通,但感觉不太优雅——有更好的方法吗?

共有2个答案

穆嘉
2023-03-14

您只需将方法签名更改为返回未来,而不是可完成的未来:

Future<String> asyncOp(String param) {
    return CompletableFuture.supplyAsync(() -> {
        log("In asyncOp");
        return "Hello " + param;
    }, preciousExecService);
}

这样,run()方法会抛出编译错误:

void run() {
    log("run");
    asyncOp("world").thenAccept(this::syncOp);
}

调用方仍然能够将返回的未来转换回可完成的未来,但这将是对API的误用,不会意外发生。

白萧迟
2023-03-14

没有任何功能可以将完成与从属操作的执行分离。当链接依赖动作的线程已经完成注册,并且您的执行者的线程完成了未来的任务时,如果没有给其他执行者,那么哪个线程应该执行依赖动作?

您将另一个操作与不同的执行器链接的方法似乎是您能得到的最好的方法。但是,重要的是要注意,在异常完成的情况下,在不评估传递给thenApply的函数的情况下传播异常。如果调用者链接了when完成句柄异常等操作,则此异常传播可能再次导致线程暴露。

另一方面,您不需要指定辅助执行程序,因为您可以使用不带执行程序参数的async方法来获取默认(公共Fork/Join)池。

所以链接<代码>。当复同步((x,y)-

 类似资料:
  • 我正在使用spring Boot2.0.4,并希望公开我的执行器endpoint。当向application.yml仅添加以下信息时,健康状况将被公开。 当我运行http://localhost:8080/acturet时,我会得到

  • 我试图在我的spring boot应用程序中公开/actuator/healthendpoint,但我的日志表明没有公开任何endpoint。我看过一些文档,其中指出健康endpoint是默认启用的唯一endpoint,但它为我返回404。 从应用程序启动的日志: 访问 /actuator 还显示未公开任何endpoint: 我看了其他几个类似的帖子,但是没有一个补丁对我有效。我在@RestCon

  • 对于一些老客户,我们希望公开一些用于运行状况监视的指标。正在查看Spring启动应用程序,其中它公开了来自本地JVM的许多有用指标。如果我在服务器中单独安装冲刺 (sprint) 引导执行器应用程序,它是否可能从远程 JVM 公开所有这些信息?还有其他建议//替代路径是值得赞赏的吗?

  • 此外,我还使用Hystrix进行断路。 我的问题是如何使Hystrix流暴露在执行器端口上? 目前,我仅通过以下代码在标准端口上公开它: 这些是我的一些依靠: 我不想使用Spring Cloud,因为这里有@EnableHystrix,它在执行器端口上提供流。

  • 我有一个web应用程序,它使用firebase进行身份验证和数据库,使用Angular4进行前端。我正在上传图像到AWS3通过我的网络应用程序和它的工作良好。 我目前正在使用angular4代码中的accessKeyId和secretAccessKey将文件直接上传到AWS S3(使用AWS SDK for javascript)。编译angular后,客户端浏览器仍然在前端使用javascrip

  • 我正在尝试实现一个通用的REST客户端,如下所示。我有自己的模型将HTTP响应表示为response T。这里T是服务调用的返回类型,它可能只是T或Ts列表。下面的代码不编译,我需要帮助。 最终调用下面的方法,