[Java多线程实现批量下载文件,层层优化多种方案实现?]

 

目录

 🎄前言:

🎄代码实现:

🎄上面的Java示例代码中,每次定时器任务执行时都会创建一个新的线程来下载文件,如果文件数量较多,可能会导致线程数过多,从而影响系统性能。为了避免这种情况,可以使用线程池来管理下载线程,从而复用线程资源,提高系统性能。

🎄进一步优化上面的代码,可以考虑使用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的性能,提高系统的并发能力。

多线程应用场景总结:

  1. 提高程序性能:多线程可以将一个任务分成多个子任务并行执行,从而提高程序的运行效率和响应速度。

  2. 处理大量数据:多线程可以同时处理大量数据,例如在数据分析、图像处理、视频编解码等领域中,多线程可以加速数据处理和计算。

  3. 并发访问:多线程可以实现并发访问,例如在Web服务器、数据库服务器等系统中,多线程可以同时处理多个请求,提高系统的并发能力和吞吐量。

  4. 交互式应用:多线程可以实现交互式应用,例如在图形界面程序、游戏等应用中,多线程可以实现用户界面和后台逻辑的并行处理,提高用户体验和程序响应速度。

  5. 实时系统:多线程可以实现实时系统,例如在航空航天、工业控制、医疗设备等领域中,多线程可以实现实时数据采集、控制和处理,保证系统的实时性和可靠性。

没有定时器的多线程批量下载文件: 

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,并且文件将保存在当前工作目录中。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是汤圆丫

怎么 给1分?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值