You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java8 CompletableFuture实现列表forEach异步调用Rest接口

实现注意事项

  • 原代码在循环外创建单个Student对象,并行场景下存在多线程属性覆盖的线程安全问题,必须改为每次循环内部创建独立Student实例
  • 不要在异步任务中直接操作非线程安全的ArrayList,改为先收集异步任务,全部完成后统一提取结果,避免并发写入异常
  • 建议自定义IO密集型线程池,避免使用CompletableFuture默认的公共ForkJoinPool,防止和其他业务异步任务争抢资源

完整改造代码

1. 自定义线程池(推荐配置)

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.*;

// 线程池参数可根据实际压测结果调整,IO密集型场景核心线程数建议设置为2*CPU核心数
private static final ExecutorService REST_CALL_POOL = new ThreadPoolExecutor(
        10,
        20,
        60L,
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(100),
        new ThreadFactoryBuilder().setNameFormat("rest-request-thread-%d").build()
);

2. 改造后的业务方法

private static List<List<Object>> getObjList(List<List<String>> combine) {
    // 1. 遍历集合创建所有异步请求任务
    List<CompletableFuture<List<Object>>> futureList = IntStream.range(0, combine.size())
            .mapToObj(index -> CompletableFuture.supplyAsync(() -> {
                // 每个任务内部创建独立Student对象,避免线程安全问题
                Student std = new Student();
                std.setList(combine.get(index));
                std.setPageId(index + 1);
                // 替换为实际的Rest调用逻辑即可
                List<Object> response = restTemplate.postForObject("你的请求接口地址", std, List.class);
                return response;
            }, REST_CALL_POOL)
            // 可选:单个请求异常捕获,避免单条失败导致整个任务报错
            .exceptionally(e -> {
                log.error("第{}个Rest请求调用失败", index + 1, e);
                // 异常场景返回默认值,可根据业务需求调整
                return Collections.emptyList();
            }))
            .collect(Collectors.toList());

    // 2. 等待所有异步任务全部执行完成
    CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).join();

    // 3. 按原始集合顺序提取所有请求结果返回
    return futureList.stream()
            .map(CompletableFuture::join)
            .collect(Collectors.toList());
}

3. 主调用逻辑调整

List<String> list1 = new ArrayList<>();
list1.add("Class1");
list1.add("Class2");
List<String> list2 = new ArrayList<>();
list2.add("Book1");
list2.add("Book2");

List<List<String>> combine = new ArrayList<>();
combine.add(list1);
combine.add(list2);
// 直接调用方法获取结果,不需要提前传入空集合
List<List<Object>> finalResponse = getObjList(combine);

关键逻辑说明

  • 用IntStream.range生成下标替代原来的AtomicInteger计数,避免多线程计数的额外开销
  • allOf方法会等待所有异步任务执行完成后再统一收集结果,返回顺序和原始combine集合的顺序完全一致
  • 线程池使用完成后如果是单次运行的程序可以主动调用REST_CALL_POOL.shutdown()关闭资源,常驻服务不需要关闭

内容的提问来源于stack exchange,提问作者LearnConcept

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 02:09:02