在Java中实现多个文件同时下载是提升程序效率的常见需求,以下是4种主流实现方案,涵盖基础语法、并发工具及第三方库的应用,并提供异常处理与性能优化建议。

多线程基础实现
通过创建线程池分配下载任务,适用于传统Java项目:
ExecutorService executor = Executors.newFixedThreadPool(5); // 控制并发数
List<String> urls = Arrays.asList("url1", "url2", "url3");
for (String url : urls) {
executor.execute(() -> {
try (InputStream in = new URL(url).openStream();
FileOutputStream out = new FileOutputStream(getFileName(url))) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
System.err.println("下载失败: " + url);
}
});
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.HOURS); // 等待所有任务完成
注意点:

- 通过线程池控制资源消耗
- 使用try-with-resources自动关闭流
- 定义合理的超时时间
Java 8并行流方案
利用Stream API简化代码结构:
List<String> urls = Arrays.asList("url1", "url2", "url3");
urls.parallelStream().forEach(url -> {
try {
Files.copy(
new URL(url).openStream(),
Paths.get(getFileName(url)),
StandardCopyOption.REPLACE_EXISTING
);
} catch (IOException e) {
System.err.println("下载异常: " + e.getMessage());
}
});
优势:

- 自动管理线程资源
- 代码简洁度高
- 适合CPU密集型任务
CompletableFuture异步方案
实现非阻塞式下载(推荐Java 8+项目使用):
List<CompletableFuture<Void>> futures = new ArrayList<>();
List<String> urls = Arrays.asList("url1", "url2", "url3");
urls.forEach(url -> {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 下载实现逻辑
}, Executors.newFixedThreadPool(5));
futures.add(future);
});
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.exceptionally(ex -> {
System.err.println("批量下载异常: " + ex.getMessage());
return null;
})
.join(); // 阻塞等待全部完成
第三方库高级方案
方案1:Apache HttpClient
CloseableHttpClient client = HttpClients.createDefault();
List<HttpGet> requests = urls.stream()
.map(HttpGet::new)
.collect(Collectors.toList());
requests.parallelStream().forEach(request -> {
try (CloseableHttpResponse response = client.execute(request)) {
HttpEntity entity = response.getEntity();
// 处理下载内容
EntityUtils.consume(entity);
} catch (IOException e) {
System.err.println("请求异常: " + request.getURI());
}
});
方案2:OkHttp
OkHttpClient client = new OkHttpClient();
List<String> urls = Arrays.asList("url1", "url2", "url3");
urls.parallelStream().forEach(url -> {
Request request = new Request.Builder().url(url).build();
try (Response response = client.newCall(request).execute()) {
try (FileOutputStream out = new FileOutputStream(getFileName(url))) {
out.write(response.body().bytes());
}
} catch (IOException e) {
System.err.println("下载中断: " + url);
}
});
最佳实践与注意事项
- 并发控制:根据网络带宽和服务器限制调整线程数
- 异常处理:
- 记录失败任务日志
- 实现断点续传机制
- 设置连接超时(推荐30-60秒)
HttpGet request = new HttpGet(url); RequestConfig config = RequestConfig.custom() .setConnectTimeout(5000) .setSocketTimeout(15000) .build(); request.setConfig(config);
- 性能优化:
- 使用缓冲流提升IO效率
- 采用连接池复用HTTP连接
- 添加进度监听功能
- 安全防护:
- 验证文件合法性(MD5/SHA校验)
- 限制下载文件类型
- 防范路径穿越攻击
引用说明
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/4815.html