文件下载是许多程序中常见的功能,尤其是在处理大量文件的下载时,常常会遇到性能瓶颈。一个常见的挑战是如何有效地管理多个文件下载任务,同时确保每个下载任务的执行不会互相干扰,并且尽量优化下载效率。
本示例实现了一个多线程文件下载管理器,支持以下功能:
- 多线程下载: 同时支持多个文件的并发下载。
- 断点续传: 支持下载中断后的恢复。
- 下载进度监控: 实时输出下载进度。
- 任务管理: 管理多个文件的下载任务,支持暂停、取消等操作。
代码实现:
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
// 文件下载管理器
public class MultiThreadedDownloadManager {
private final ExecutorService downloadExecutor;
private final Map<String, DownloadTask> downloadTasks;
private final AtomicInteger activeDownloads;
public MultiThreadedDownloadManager(int maxThreads) {
this.downloadExecutor = Executors.newFixedThreadPool(maxThreads);
this.downloadTasks = new HashMap<>();
this.activeDownloads = new AtomicInteger(0);
}
// 启动下载任务
public void downloadFile(String fileUrl, String destinationPath) {
DownloadTask task = new DownloadTask(fileUrl, destinationPath);
downloadTasks.put(fileUrl, task);
downloadExecutor.submit(task);
}
// 下载任务
private class DownloadTask implements Runnable {
private final String fileUrl;
private final String destinationPath;
private volatile boolean paused = false;
private volatile boolean cancelled = false;
public DownloadTask(String fileUrl, String destinationPath) {
this.fileUrl = fileUrl;
this.destinationPath = destinationPath;
}
@Override
public void run() {
try {
downloadFileWithResume(fileUrl, destinationPath);
} catch (IOException e) {
e.printStackTrace();
}
}
// 下载文件,支持断点续传
private void downloadFileWithResume(String fileUrl, String destinationPath) throws IOException {
URL url = new URL(fileUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 如果文件已经下载过,断点续传
File destinationFile = new File(destinationPath);
long existingFileSize = 0;
if (destinationFile.exists()) {
existingFileSize = destinationFile.length();
connection.setRequestProperty("Range", "bytes=" + existingFileSize + "-");
}
// 获取文件大小
long totalSize = connection.getContentLengthLong();
try (InputStream inputStream = connection.getInputStream();
RandomAccessFile outputFile = new RandomAccessFile(destinationFile, "rw")) {
// 如果文件存在且大小相等,说明下载完成
if (existingFileSize >= totalSize) {
System.out.println("File already fully downloaded: " + destinationPath);
return;
}
outputFile.seek(existingFileSize);
byte[] buffer = new byte[1024];
int bytesRead;
long downloadedBytes = existingFileSize;
long lastUpdateTime = System.currentTimeMillis();
while ((bytesRead = inputStream.read(buffer)) != -1 && !cancelled) {
if (paused) {
synchronized (this) {
wait(); // 等待恢复
}
}
outputFile.write(buffer, 0, bytesRead);
downloadedBytes += bytesRead;
// 显示下载进度
long currentTime = System.currentTimeMillis();
if (currentTime - lastUpdateTime >= 1000) {
long progress = (downloadedBytes * 100) / totalSize;
System.out.println("Downloading: " + fileUrl + " - " + progress + "%");
lastUpdateTime = currentTime;
}
}
if (cancelled) {
System.out.println("Download cancelled: " + fileUrl);
} else {
System.out.println("Download completed: " + fileUrl);
}
} finally {
activeDownloads.decrementAndGet();
}
}
// 暂停下载
public void pauseDownload() {
paused = true;
}
// 恢复下载
public synchronized void resumeDownload() {
paused = false;
notify();
}
// 取消下载
public void cancelDownload() {
cancelled = true;
}
}
// 停止所有下载任务
public void shutdown() {
downloadExecutor.shutdown();
}
// 获取当前正在下载的任务数量
public int getActiveDownloadCount() {
return activeDownloads.get();
}
// 测试方法
public static void main(String[] args) throws InterruptedException {
MultiThreadedDownloadManager downloadManager = new MultiThreadedDownloadManager(3);
// 启动下载任务
downloadManager.downloadFile("https://example.com/file1.zip", "file1.zip");
downloadManager.downloadFile("https://example.com/file2.zip", "file2.zip");
downloadManager.downloadFile("https://example.com/file3.zip", "file3.zip");
// 模拟暂停和恢复
Thread.sleep(5000);
downloadManager.downloadTasks.get("https://example.com/file1.zip").pauseDownload();
System.out.println("Download paused for file1.zip");
Thread.sleep(5000);
downloadManager.downloadTasks.get("https://example.com/file1.zip").resumeDownload();
System.out.println("Download resumed for file1.zip");
// 等待所有下载任务完成
while (downloadManager.getActiveDownloadCount() > 0) {
Thread.sleep(1000);
}
// 关闭下载管理器
downloadManager.shutdown();
}
}
代码解析:
-
下载管理器:
MultiThreadedDownloadManager类管理多个下载任务。它使用线程池(ExecutorService)来同时处理多个文件的下载任务,避免阻塞主线程。downloadExecutor是线程池,能够并发执行多个下载任务,最大线程数由用户传入。downloadTasks是一个存储当前下载任务的映射,方便对特定任务进行操作(如暂停、恢复、取消)。
-
下载任务:
- 每个下载任务通过
DownloadTask类来管理。任务可以暂停、恢复或取消。下载过程中,任务会定期更新进度,并在每秒钟显示当前下载的百分比。 downloadFileWithResume方法实现了断点续传的功能。它检查文件是否已经存在,如果存在则从上次下载位置继续下载。- 使用
RandomAccessFile来实现断点续传功能,通过seek()方法跳过已下载的部分。
- 每个下载任务通过
-
任务控制:
- 暂停: 使用
pauseDownload方法将paused标志设置为true,并使用wait()来阻塞任务。 - 恢复: 使用
resumeDownload方法将paused设置为false,并通过notify()恢复下载任务。 - 取消: 使用
cancelDownload方法将cancelled设置为true,终止下载。
- 暂停: 使用
-
进度更新:
- 每当下载一定的字节后,更新下载进度。进度以百分比的形式显示在控制台上。
-
任务管理:
- 使用
activeDownloads来跟踪当前正在下载的任务数量,方便在主线程中监控任务执行状态。
- 使用
使用说明:
-
初始化下载管理器:
- 创建一个
MultiThreadedDownloadManager实例,并设置最大线程数(例如 3 个线程并发下载)。
MultiThreadedDownloadManager downloadManager = new MultiThreadedDownloadManager(3); - 创建一个
-
启动文件下载:
- 使用
downloadFile方法启动一个下载任务,第一个参数为文件 URL,第二个参数为保存文件的本地路径。
downloadManager.downloadFile("https://example.com/file1.zip", "file1.zip"); - 使用
-
暂停和恢复下载:
- 使用
pauseDownload暂停下载任务,使用resumeDownload恢复下载任务。
downloadManager.downloadTasks.get("https://example.com/file1.zip").pauseDownload(); downloadManager.downloadTasks.get("https://example.com/file1.zip").resumeDownload(); - 使用
-
取消下载:
- 使用
cancelDownload取消一个下载任务。
downloadManager.downloadTasks.get("https://example.com/file1.zip").cancelDownload(); - 使用
-
关闭下载管理器:
- 使用
shutdown方法关闭下载管理器,停止所有下载任务。
downloadManager.shutdown(); - 使用
示例输出:
Downloading: https://example.com/file1.zip - 10%
Downloading: https://example.com/file2.zip - 20%
Downloading: https://example.com/file1.zip - 20%
Download paused for file1.zip
Downloading: https://example.com/file1.zip - 30%
Download resumed for file1.zip
Downloading: https://example.com/file1.zip - 50%
Downloading: https://example.com/file3.zip - 10%
Download completed: https://example.com/file1.zip
Download completed: https://example.com/file2.zip
Download completed: https://example.com/file3.zip
总结:
这个多线程文件下载管理器实现了一个功能丰富且高效的下载系统。它不仅支持多线程并发下载,还可以进行断点续传、进度显示和任务管理等。对于需要同时下载多个文件或对下载任务进行控制的场景,它提供了极大的便利和性能优化。
5871

被折叠的 条评论
为什么被折叠?



