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

Java17+Spring Boot批量调用第三方API超时问题求解决方案

解决思路

1. 优化多线程线程池配置

之前的多线程方案大概率是参数不合理导致的问题,第三方API普遍有并发调用限制,盲目开大量线程只会触发限流或耗尽连接池:

  • 先确认API允许的并发调用上限,比如允许同时10次调用,就把线程池核心线程数设为10,最大线程数设为15左右,保留缓冲空间;
  • 用ThreadPoolExecutor自定义线程池,搭配有界任务队列,拒绝策略选CallerRunsPolicy,避免任务丢失的同时防止线程池过载;
  • 示例代码:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    10, // 核心线程数
    15, // 最大线程数
    60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(100), // 有界任务队列
    Executors.defaultThreadFactory(),
    new ThreadPoolExecutor.CallerRunsPolicy()
);

2. 分批次异步处理

如果API不支持批量查询,就分批次提交异步任务,避免瞬间打满API并发限制:

  • 每次提交50-100个任务到线程池,等当前批次全部完成后再提交下一批,防止本地任务队列溢出;
  • 结合Spring的CompletableFuture做异步编排,用CompletableFuture.allOf()等待批次任务完成;
  • 示例代码:
int batchSize = 50;
List<Owner> owners = ownerRepository.findAll();
for (int i = 0; i < owners.size(); i += batchSize) {
    int end = Math.min(i + batchSize, owners.size());
    List<CompletableFuture<Void>> futures = owners.subList(i, end).stream()
        .map(owner -> CompletableFuture.runAsync(() -> {
            // 调用API获取共有人信息
            CoOwner coOwner = thirdPartyApiClient.getCoOwner(owner.getId());
            owner.setCoOwner(coOwner);
        }, executor))
        .collect(Collectors.toList());
    // 等待当前批次完成
    CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
}
// 统一写入文件
saveToFile(owners);

3. 增加重试与超时控制

API调用偶尔会出现超时或失败,不加处理会拖慢整体进度:

  • 用Guava Retryer或Spring的@Retryable实现重试逻辑,针对IOException、TimeoutException等异常重试3次,每次间隔1秒;
  • 给每个API调用设置超时时间,比如用HttpClient设置5秒连接超时和读取超时,避免单个请求卡住;
  • 示例代码:
HttpClient httpClient = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(5))
    .build();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://third-party-api.com/co-owner/" + ownerId))
    .timeout(Duration.ofSeconds(5))
    .build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

4. 断点续传机制

10000条数据中途失败后从头再来太浪费时间,可通过中间态持久化实现断点续传:

  • 给所有者表新增processed字段,默认false,处理完一条就标记为true,每次启动只查询未处理的记录;
  • 或者用临时文件记录已处理的ID列表,启动时读取列表跳过已处理数据。

5. 离线异步任务调度

如果不需要实时获取数据,把任务改成离线定时执行:

  • 用Spring的@Scheduled注解设置每天凌晨低峰期执行,比如@Scheduled(cron = "0 0 2 * * ?");
  • 执行过程中按批次打印日志,方便跟踪进度和排查问题。

6. 优化数据库查询性能

有时候问题根源在数据库查询:

  • 给所有者表的查询字段加索引,确保findAll()快速返回数据;
  • 如果一次性查询10000条内存压力大,改用分页查询,每次查1000条,处理完再查下一页。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 05:45:02