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

Java中调用方法时如何等待指定Thread执行完成?多线程下载需求咨询

实现方案

1. 定义封装类统一管理页面状态

不要直接用ArrayList存下载链接,先封装一个类存每个页面对应的下载状态和结果,方便后续状态判断:

public class HtmlPageItem {
    // 原始下载链接
    private final String downloadUrl;
    // 下载完成后存储的本地文件路径,未下载时为null
    private String localFilePath;
    // 下载完成标记
    private boolean isDownloaded = false;
    // 下载失败标记
    private boolean isDownloadFailed = false;

    public HtmlPageItem(String downloadUrl) {
        this.downloadUrl = downloadUrl;
    }

    // 下面的getter、setter方法直接用IDE自动生成即可
    public String getDownloadUrl() { return downloadUrl; }
    public String getLocalFilePath() { return localFilePath; }
    public void setLocalFilePath(String localFilePath) { this.localFilePath = localFilePath; }
    public boolean isDownloaded() { return isDownloaded; }
    public void setDownloaded(boolean downloaded) { isDownloaded = downloaded; }
    public boolean isDownloadFailed() { return isDownloadFailed; }
    public void setDownloadFailed(boolean downloadFailed) { isDownloadFailed = downloadFailed; }
}

原来的ArrayList<String>替换为List<HtmlPageItem> pageList,初始化时把所有下载链接转为HtmlPageItem对象存入即可。

2. 实现后台下载逻辑

用JDK自带的ExecutorService线程池管理下载任务,不用手动管理线程,逻辑更简单,优先下载第一个页面,下载完成后立刻展示,剩余页面后台并行下载:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.SwingUtilities;
import javax.swing.JOptionPane;

// 类成员变量,全局只需要初始化一次线程池
private ExecutorService downloadPool = Executors.newFixedThreadPool(3); // 3个线程并行下载,可自行调整数量
// 记录当前展示的页面下标
private int currentPageIndex = 0;

// 页面初始化时调用该方法启动下载
private void startAllDownload(List<HtmlPageItem> pageList) {
    if (pageList == null || pageList.isEmpty()) return;
    // 优先提交第一个页面的下载任务
    HtmlPageItem firstPage = pageList.get(0);
    downloadPool.submit(() -> {
        // 执行下载,替换为你自己的下载逻辑
        boolean downloadSuccess = doDownload(firstPage);
        if (downloadSuccess) {
            // JxBrowser的UI操作必须切到主线程执行,如果你用JavaFX就把SwingUtilities换成Platform.runLater
            SwingUtilities.invokeLater(() -> {
                // 加载第一个页面的本地文件
                browser.loadURL("file://" + firstPage.getLocalFilePath());
            });
        }
        // 第一个页面下载完成后,提交剩余所有页面的下载任务
        for (int i = 1; i < pageList.size(); i++) {
            HtmlPageItem item = pageList.get(i);
            downloadPool.submit(() -> doDownload(item));
        }
    });
}

// 下载文件的具体逻辑,替换为你自己的下载代码即可
private boolean doDownload(HtmlPageItem pageItem) {
    try {
        String targetUrl = pageItem.getDownloadUrl();
        // 你原来的下载逻辑:把targetUrl对应的HTML存到本地,拿到存储路径
        String savePath = "你的本地存储目录/" + System.currentTimeMillis() + ".html";
        // ......你的原有下载代码......

        // 下载成功后更新状态
        pageItem.setLocalFilePath(savePath);
        pageItem.setDownloaded(true);
        return true;
    } catch (Exception e) {
        pageItem.setDownloadFailed(true);
        e.printStackTrace();
        return false;
    }
}

3. 实现next/prev按钮点击逻辑

点击时先判断目标页面的下载状态,未下载完成直接弹提示:

// next按钮点击事件
private void onNextClick() {
    int nextIndex = currentPageIndex + 1;
    // 循环切换逻辑,到最后一个就回到第一个
    if (nextIndex >= pageList.size()) {
        nextIndex = 0;
    }
    HtmlPageItem targetPage = pageList.get(nextIndex);
    if (!targetPage.isDownloaded()) {
        JOptionPane.showMessageDialog(null, "当前页面还在下载中,请稍后再试");
        return;
    }
    if (targetPage.isDownloadFailed()) {
        JOptionPane.showMessageDialog(null, "当前页面下载失败");
        return;
    }
    // 加载目标页面
    browser.loadURL("file://" + targetPage.getLocalFilePath());
    currentPageIndex = nextIndex;
}

// prev按钮点击事件
private void onPrevClick() {
    int prevIndex = currentPageIndex - 1;
    // 循环切换逻辑,到第一个就回到最后一个
    if (prevIndex < 0) {
        prevIndex = pageList.size() - 1;
    }
    HtmlPageItem targetPage = pageList.get(prevIndex);
    if (!targetPage.isDownloaded()) {
        JOptionPane.showMessageDialog(null, "当前页面还在下载中,请稍后再试");
        return;
    }
    if (targetPage.isDownloadFailed()) {
        JOptionPane.showMessageDialog(null, "当前页面下载失败");
        return;
    }
    // 加载目标页面
    browser.loadURL("file://" + targetPage.getLocalFilePath());
    currentPageIndex = prevIndex;
}

额外注意

  • 程序退出时记得调用downloadPool.shutdown()关闭线程池,避免资源泄漏
  • 如果需要支持下载重试,在失败提示的弹窗里加重试按钮,重新提交对应页面的下载任务即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 01:24:04