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

如何通过多线程或异步调用优化ArrayList批量REST请求?

批量异步/多线程调用REST接口实现方案

针对单线程批量调用耗时过长的问题,下面给出两种Java实现方案,核心都是利用多线程/异步IO并行处理批量请求,缩短总耗时。

方案一:基于CompletableFuture的异步调用

利用Java 8+的CompletableFuture配合线程池,将每个批量REST调用包装成异步任务,并行执行后统一等待结果,适合需要异步回调或结果聚合的场景。

代码示例

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class AsyncRestBatchProcessor {
    // 根据REST接口并发限制调整线程池大小,比如接口允许20并发就设为20
    private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(20);
    private static final int BATCH_SIZE = 100;

    public static void main(String[] args) throws InterruptedException {
        // 模拟10000条记录的ArrayList
        List<String> records = new ArrayList<>(10000);
        for (int i = 0; i < 10000; i++) {
            records.add("record_" + i);
        }

        // 分割成指定大小的批量
        List<List<String>> batches = splitIntoBatches(records, BATCH_SIZE);
        List<CompletableFuture<Void>> futures = new ArrayList<>();

        // 提交所有异步任务
        for (List<String> batch : batches) {
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                try {
                    // 替换为实际REST接口调用逻辑
                    callRestApi(batch);
                } catch (Exception e) {
                    // 单个批量任务异常处理,比如日志记录
                    System.err.println("批量任务失败,记录数:" + batch.size() + ",错误:" + e.getMessage());
                }
            }, EXECUTOR);
            futures.add(future);
        }

        // 等待所有异步任务完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

        // 关闭线程池,释放资源
        EXECUTOR.shutdown();
        EXECUTOR.awaitTermination(1, TimeUnit.HOURS);
    }

    // 通用列表分割方法
    private static <T> List<List<T>> splitIntoBatches(List<T> list, int batchSize) {
        List<List<T>> batches = new ArrayList<>();
        for (int i = 0; i < list.size(); i += batchSize) {
            int end = Math.min(i + batchSize, list.size());
            batches.add(new ArrayList<>(list.subList(i, end)));
        }
        return batches;
    }

    // 模拟REST接口调用
    private static void callRestApi(List<String> batch) throws InterruptedException {
        // 实际场景替换为RestTemplate/WebClient等HTTP客户端调用
        System.out.println("处理批量,记录数:" + batch.size() + ",线程:" + Thread.currentThread().getName());
        // 模拟接口耗时(原单线程单批约9秒,这里用1秒演示)
        TimeUnit.SECONDS.sleep(1);
    }
}

方案二:基于线程池的多线程批量处理

如果不需要异步回调逻辑,直接用ExecutorService提交Runnable任务,是更简洁的多线程实现方式。

代码示例

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadPoolRestBatchProcessor {
    private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(20);
    private static final int BATCH_SIZE = 100;

    public static void main(String[] args) throws InterruptedException {
        List<String> records = new ArrayList<>(10000);
        for (int i = 0; i < 10000; i++) {
            records.add("record_" + i);
        }

        List<List<String>> batches = splitIntoBatches(records, BATCH_SIZE);

        // 提交所有批量任务到线程池
        for (List<String> batch : batches) {
            EXECUTOR.submit(() -> {
                try {
                    callRestApi(batch);
                } catch (Exception e) {
                    System.err.println("批量任务失败:" + e.getMessage());
                }
            });
        }

        // 关闭线程池并等待所有任务完成
        EXECUTOR.shutdown();
        if (!EXECUTOR.awaitTermination(1, TimeUnit.HOURS)) {
            // 超时未完成时强制关闭
            EXECUTOR.shutdownNow();
        }
    }

    private static <T> List<List<T>> splitIntoBatches(List<T> list, int batchSize) {
        List<List<T>> batches = new ArrayList<>();
        for (int i = 0; i < list.size(); i += batchSize) {
            int end = Math.min(i + batchSize, list.size());
            batches.add(new ArrayList<>(list.subList(i, end)));
        }
        return batches;
    }

    private static void callRestApi(List<String> batch) throws InterruptedException {
        System.out.println("处理批量,记录数:" + batch.size() + ",线程:" + Thread.currentThread().getName());
        TimeUnit.SECONDS.sleep(1);
    }
}

关键注意事项

  • 线程池大小:需根据REST接口的并发限制、服务器资源调整,避免过大导致接口限流或服务器过载。比如接口允许20并发,线程池核心/最大线程数就设为20。
  • 异常处理:每个批量任务内部必须捕获异常,防止单个任务失败中断整个流程。
  • 资源释放:必须调用executor.shutdown()和awaitTermination()关闭线程池,避免JVM无法正常退出。
  • 实际HTTP调用:将示例中的callRestApi替换为实际客户端实现,比如用WebClient(异步非阻塞)可进一步提升性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 17:55:28