java - 如何使用 CompletableFuture 并行化 Web 服务请求?

标签 java spring completable-future

我有一个 servlet 请求,它基本上请求输入日期给出的数据。由于我有多个日期,因此我必须发送多个请求,然后汇总结果。例如:

List<Result> results = new ArrayList<>();

for (LocalDate date : dates) {
    ServletReq req = new ServletReq(date);

    try {
        ServletRsp rsp = webservice.send(req);
        results.addAll(rsp.getResults());
    } catch (SpecificException e) {
        //just ignore this result and continue
    }
}

问题:如何并行化上面的代码?意思是:发送多个ServletReq async,并将结果收集到列表中。等待所有请求完成(可能超时),并忽略 SpecificException .

我是这样开始的,但我既不知道这是否是正确的方向,也没有成功地完全转移上面的代码。特别是关于要忽略的异常。

ExecutorService service = Executors.newCachedThreadPool();
List<CompletableFuture<ServletRsp>> futures = new ArrayList<>();

for (LocalDate date : dates) {
    ServletReq req = new ServletReq(date);
    CompletableFuture future = CompletableFuture.supplyAsync(() -> webservice.send(req), service);
    futures.add(future);
}

CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).join();

到目前为止,但是:我怎样才能打电话rsp.getResults()在异步结果上,并将所有内容放入 list 。我怎么能忽略 SpecificException在异步执行期间? (我无法修改 webservice.send() 方法!)。

最佳答案

  • 在供应商内捕获它们并返回,例如null 。只有当你确实除了异常(exception)什么都不做时才这样做。要获得结果 future.get()你必须处理nullExecutionException

例如

CompletableFuture<ServletRsp> future = CompletableFuture.supplyAsync(() -> {
    try {
        return webservice.send(new ServletReq(date));
    } catch (SpecificException e) {
        return null;
    }
});
  • 将它们重新抛出(自定义?)RuntimeException这样你就不会失去它们。现在您最终只处理异常,但有些异常是双重包装的。
  • 手动完成 future 。

例如

CompletableFuture<ServletRsp> future = new CompletableFuture<>();
service.execute(() -> {
    try {
        future.complete(webservice.send(new ServletReq(date));
    } catch (SpecificException e) {
        future.completeExceptionally(e);
    }
});
futures.add(future);

除了 ExecutionException 之外不再需要包装。 CompletableFuture.supplyAsync正是这样做的,但没有代码来处理检查的异常。

  • 只需使用旧的 ExecutorService#submit(Callable<T> callable)接受抛出以下代码的方法:

例如

List<Callable<String>> tasks = dates.stream()
        .map(d -> (Callable<ServletRsp>) () -> send(new ServletReq(d)))
        .collect(Collectors.toList());
List<Future<ServletRsp>> completed = service.invokeAll(tasks);

关于java - 如何使用 CompletableFuture 并行化 Web 服务请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45030110/

相关文章:

java - 为什么 JTable 中的 boolean 值显示为 true/false 而不是复选框?

java - 如何将 bean 注入(inject) @Controller 类

java - 从Spring Boot连接到Heroku Postgres

java - 按顺序运行异步操作

重新部署为 Web 应用程序时,ClassLoader 出现 Java JNI GDAL native 库错误

java - 如何分组然后使用java8流列出toMap

java - 使用默认值中断 CompletableFuture

java - 在 Java 中使用 CompletableFuture 并行执行 for 循环并记录执行

java - 更大尺寸的 ParallelStream toArray Java8

spring - 在 spring mvc 中使用 @component 注解注释的 Spring 类的范围是什么?