目录
🎄进一步优化上面的代码,可以考虑使用Java 8中新增的CompletableFuture类来实现异步下载文件,从而更好地利用多核CPU的性能,提高系统的并发能力。
🎄前言:
笔记,这个主要就是多看看实现的思路,希望对你有帮助.......
🎄代码实现:
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class FileDownloader {
// 定义下载任务类
private static class DownloadTask implements Runnable {
private String url;
private String filename;
public DownloadTask(String url, String filename) {
this.url = url;
this.filename = filename;
}
@Override
public void run() {
try {
URL urlObj = new URL(url);
InputStream in = urlObj.openStream();
FileOutputStream out = new FileOutputStream(filename);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 定义定时器任务类
private static class DownloadTimerTask extends TimerTask {
private List<String[]> fileList;
public DownloadTimerTask(List<String[]> fileList) {
this.fileList = fileList;
}
@Override
public void run() {
for (String[] file : fileList) {
// 创建下载任务并启动
DownloadTask task = new DownloadTask(file[0], file[1]);
Thread thread = new Thread(task);
thread.start();
}
}
}
public static void main(String[] args) {
// 定义要下载的文件列表
List<String[]> fileList = new ArrayList<>();
fileList.add(new String[]{"http://example.com/file1.txt", "file1.txt"});
fileList.add(new String[]{"http://example.com/file2.txt", "file2.txt"});
fileList.add(new String[]{"http://example.com/file3.txt", "file3.txt"});
// 创建定时器并启动
Timer timer = new Timer();
timer.schedule(new DownloadTimerTask(fileList), 0, 60000); // 每隔60秒执行一次任务
}
}
DownloadTask
类用于下载文件,接受两个参数:文件的URL和保存的文件名。DownloadTimerTask
类是定时器任务类,接受一个参数:要下载的文件列表。在定时器任务中,每隔一定时间就会遍历文件列表,为每个文件创建一个下载任务并启动。最后,创建定时器并启动。在本例中,定时器的间隔时间为60秒,即每隔60秒就会执行一次下载任务。- 使用了
java.net.URL
类来打开文件的URL连接,然后使用java.io.InputStream
类来读取文件内容,最后使用java.io.FileOutputStream
类将文件内容写入到本地文件中。- 在
run
方法中,首先使用java.net.URL
类打开文件的URL连接,然后使用java.io.InputStream
类读取文件内容,每次读取1024字节,直到读取完整个文件。最后,使用java.io.FileOutputStream
类将文件内容写入到本地文件中,并关闭输入输出流。
🎄上面的Java示例代码中,每次定时器任务执行时都会创建一个新的线程来下载文件,如果文件数量较多,可能会导致线程数过多,从而影响系统性能。为了避免这种情况,可以使用线程池来管理下载线程,从而复用线程资源,提高系统性能。
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FileDownloader {
// 定义下载任务类
private static class DownloadTask implements Runnable {
private String url;
private String filename;
public DownloadTask(String url, String filename) {
this.url = url;
this.filename = filename;
}
@Override
public void run() {
try {
URL urlObj = new URL(url);
InputStream in = urlObj.openStream();
FileOutputStream out = new FileOutputStream(filename);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 定义定时器任务类
private static class DownloadTimerTask extends TimerTask {
private List<String[]> fileList;
private ExecutorService executorService;
public DownloadTimerTask(List<String[]> fileList) {
this.fileList = fileList;
this.executorService = Executors.newFixedThreadPool(10); // 创建线程池,最多同时执行10个下载任务
}
@Override
public void run() {
for (String[] file : fileList) {
// 提交下载任务到线程池
DownloadTask task = new DownloadTask(file[0], file[1]);
executorService.submit(task);
}
}
}
public static void main(String[] args) {
// 定义要下载的文件列表
List<String[]> fileList = new ArrayList<>();
fileList.add(new String[]{"http://example.com/file1.txt", "file1.txt"});
fileList.add(new String[]{"http://example.com/file2.txt", "file2.txt"});
fileList.add(new String[]{"http://example.com/file3.txt", "file3.txt"});
// 创建定时器并启动
Timer timer = new Timer();
timer.schedule(new DownloadTimerTask(fileList), 0, 60000); // 每隔60秒执行一次任务
}
}
- 在优化后的代码中,
DownloadTimerTask
类的构造函数中创建了一个线程池,最多同时执行10个下载任务。在定时器任务中,将下载任务提交到线程池中执行,从而复用线程资源,提高系统性能。
🎄进一步优化上面的代码,可以考虑使用Java 8中新增的CompletableFuture
类来实现异步下载文件,从而更好地利用多核CPU的性能,提高系统的并发能力。
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CompletableFuture;
public class FileDownloader {
// 定义下载任务类
private static class DownloadTask {
private String url;
private String filename;
public DownloadTask(String url, String filename) {
this.url = url;
this.filename = filename;
}
public void run() {
try {
URL urlObj = new URL(url);
InputStream in = urlObj.openStream();
FileOutputStream out = new FileOutputStream(filename);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 定义定时器任务类
private static class DownloadTimerTask extends TimerTask {
private List<String[]> fileList;
public DownloadTimerTask(List<String[]> fileList) {
this.fileList = fileList;
}
@Override
public void run() {
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (String[] file : fileList) {
// 创建异步下载任务并启动
CompletableFuture<Void> future = CompletableFuture.runAsync(new DownloadTask(file[0], file[1])::run);
futures.add(future);
}
// 等待所有异步下载任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
}
}
public static void main(String[] args) {
// 定义要下载的文件列表
List<String[]> fileList = new ArrayList<>();
fileList.add(new String[]{"http://example.com/file1.txt", "file1.txt"});
fileList.add(new String[]{"http://example.com/file2.txt", "file2.txt"});
fileList.add(new String[]{"http://example.com/file3.txt", "file3.txt"});
// 创建定时器并启动
Timer timer = new Timer();
timer.schedule(new DownloadTimerTask(fileList), 0, 60000); // 每隔60秒执行一次任务
}
}
- 在进一步优化后的代码中,
DownloadTask
类变成了普通的类,不再实现Runnable
接口。在DownloadTimerTask
类中,使用CompletableFuture
类创建异步下载任务,并将所有异步下载任务添加到一个列表中。然后,使用CompletableFuture.allOf
方法等待所有异步下载任务完成。由于CompletableFuture
类内部使用了线程池来管理异步任务,因此可以更好地利用多核CPU的性能,提高系统的并发能力。
多线程应用场景总结:
-
提高程序性能:多线程可以将一个任务分成多个子任务并行执行,从而提高程序的运行效率和响应速度。
-
处理大量数据:多线程可以同时处理大量数据,例如在数据分析、图像处理、视频编解码等领域中,多线程可以加速数据处理和计算。
-
并发访问:多线程可以实现并发访问,例如在Web服务器、数据库服务器等系统中,多线程可以同时处理多个请求,提高系统的并发能力和吞吐量。
-
交互式应用:多线程可以实现交互式应用,例如在图形界面程序、游戏等应用中,多线程可以实现用户界面和后台逻辑的并行处理,提高用户体验和程序响应速度。
-
实时系统:多线程可以实现实时系统,例如在航空航天、工业控制、医疗设备等领域中,多线程可以实现实时数据采集、控制和处理,保证系统的实时性和可靠性。
没有定时器的多线程批量下载文件:
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class MultiThreadDownloader {
private static final int BUFFER_SIZE = 4096;
private static final int NUM_THREADS = 4;
public static void main(String[] args) {
List<String> urls = new ArrayList<>();
urls.add("https://example.com/file1.txt");
urls.add("https://example.com/file2.txt");
urls.add("https://example.com/file3.txt");
urls.add("https://example.com/file4.txt");
int numFiles = urls.size();
int numThreads = Math.min(numFiles, NUM_THREADS);
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < numThreads; i++) {
int start = i * numFiles / numThreads;
int end = (i + 1) * numFiles / numThreads;
List<String> subUrls = urls.subList(start, end);
Thread thread = new DownloadThread(subUrls);
thread.start();
threads.add(thread);
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static class DownloadThread extends Thread {
private List<String> urls;
public DownloadThread(List<String> urls) {
this.urls = urls;
}
@Override
public void run() {
for (String url : urls) {
try {
downloadFile(url);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void downloadFile(String urlStr) throws IOException {
URL url = new URL(urlStr);
String fileName = url.getFile().substring(url.getFile().lastIndexOf('/') + 1);
BufferedInputStream in = new BufferedInputStream(url.openStream());
FileOutputStream out = new FileOutputStream(fileName);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
out.write(buffer, 0, bytesRead);
}
in.close();
out.close();
}
}
}
该示例代码将下载的文件 URL 存储在一个列表中,然后将其分成多个子列表,每个子列表由一个线程处理。每个线程都会遍历其子列表中的 URL,并下载每个文件。下载的文件将保存在当前工作目录中,文件名将从 URL 中提取。
这段代码中的 downloadFile
方法会从给定的 URL 中下载文件,并将其保存在当前工作目录中。文件名是从 URL 中提取的,即从 URL 的最后一个斜杠(/
)后面的部分开始,直到 URL 的末尾。例如,如果 URL 是 https://example.com/files/file1.txt
,则文件名将是 file1.txt
,并且文件将保存在当前工作目录中。