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

Java多线程场景下ExecutorService调用Jsoup抓取超时自动重试问题咨询

可行解决方案

以下两种方案都可以满足你的需求,可根据实际场景选择:

方案1:Jsoup内置超时+任务内重试(最简化实现)

直接利用Jsoup自带的超时配置,把单次请求的连接、读取超时都设为2秒,再给每个任务加重试逻辑即可,不需要修改原有线程池的调度逻辑。

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.concurrent.*;

// 封装通用带重试的抓取方法
private Document crawlWebsite(String url, int maxRetryTimes) throws IOException, InterruptedException {
    int currentRetry = 0;
    while (currentRetry < maxRetryTimes) {
        try {
            // 直接设置Jsoup超时为2000毫秒(2秒),到达阈值直接抛出超时异常
            return Jsoup.connect(url)
                    .timeout(2000)
                    .get();
        } catch (SocketTimeoutException e) {
            currentRetry++;
            if (currentRetry >= maxRetryTimes) {
                throw e; // 重试次数耗尽后再抛出异常
            }
            // 可选:重试前加短延迟,避免触发目标站反爬策略
            Thread.sleep(300 + currentRetry * 200);
        }
    }
    return null;
}

修改原有任务提交逻辑:

ExecutorService es = Executors.newCachedThreadPool();

// 提交三个抓取任务,每个最多重试3次
Future<Document> task1 = es.submit(() -> crawlWebsite("网站1地址", 3));
Future<Document> task2 = es.submit(() -> crawlWebsite("网站2地址", 3));
Future<Document> task3 = es.submit(() -> crawlWebsite("网站3地址", 3));

// 后续可通过future.get()获取抓取结果
es.awaitTermination(10, TimeUnit.SECONDS);
es.shutdown();

方案2:全局超时监控(适合任务逻辑复杂的场景)

如果你的任务除了Jsoup抓取还有其他逻辑可能超时,或者不能修改Jsoup本身的配置,可以用Future的超时检测机制,单独调度监控线程判断任务是否超时,超时后取消原任务重新提交。

ExecutorService es = Executors.newCachedThreadPool();
// 新增定时线程池做超时监控
ScheduledExecutorService monitorPool = Executors.newScheduledThreadPool(1);
int maxRetryTimes = 3;

// 封装带重试逻辑的任务,以task1为例
Runnable crawlTask1 = new Runnable() {
    int retryCount = 0;
    @Override
    public void run() {
        if (retryCount >= maxRetryTimes) {
            System.out.println("任务1重试次数耗尽,执行失败");
            return;
        }
        Future<?> taskFuture = es.submit(() -> {
            // 原有Jsoup抓取逻辑,无需修改
            Document doc = Jsoup.connect("网站1地址").get();
            // 处理抓取结果
        });
        // 2秒后检测任务是否完成
        monitorPool.schedule(() -> {
            if (!taskFuture.isDone()) {
                taskFuture.cancel(true); // 终止超时任务
                retryCount++;
                es.submit(this); // 重新提交任务重试
            }
        }, 2, TimeUnit.SECONDS);
    }
};

// 提交三个任务
es.submit(crawlTask1);
// task2、task3按同样逻辑封装后提交

// 所有任务执行完成后关闭两个线程池即可

注意事项

  • 重试时建议加递增延迟,避免短时间频繁请求被目标网站拦截
  • Jsoup的IO操作默认响应中断,调用future.cancel(true)可以正常终止阻塞中的连接
  • 如果需要等待三个任务全部完成再执行后续逻辑,可以搭配CountDownLatch做同步控制

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 05:06:03