Java多线程下载文件

优化:合理利用服务器资源,将资源利用最大化,加快下载速度

一般有两种方式:

  • 线程池里面有N个线程,多线程下载单个文件,将网络路径的文件流切割成多快,每个线程下载一小部分,然后写入到文件里面,组成一个文件
  • 当有很多个文件需要下载的时候,调用某个方法,有个线程池,线程池大小假定是10,当有10个文件过来的时候,每个线程去下载一个文件即可

多线程如果只知道Thread和Runnable,那你就Out了,Java1.5以后有个concurrent包,就是Java并发编程。

N个线程下载单个文件

定义一个单个线程下载的部分

public class DownloadWithRange implements Runnable {private String urlLocation;private String filePath;private long start;private long end;DownloadWithRange(String urlLocation, String filePath, long start, long end) {this.urlLocation = urlLocation;this.filePath = filePath;this.start = start;this.end = end;}@Overridepublic void run() {try {HttpURLConnection conn = getHttp();conn.setRequestProperty("Range", "bytes=" + start + "-" + end);File file = new File(filePath);RandomAccessFile out = null;if (file != null) {out = new RandomAccessFile(file, "rw");}out.seek(start);InputStream in = conn.getInputStream();byte[] b = new byte[1024];int len = 0;while ((len = in.read(b)) >= 0) {out.write(b, 0, len);}in.close();out.close();} catch (Exception e) {e.getMessage();}}public HttpURLConnection getHttp() throws IOException {URL url = null;if (urlLocation != null) {url = new URL(urlLocation);}HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setReadTimeout(5000);conn.setRequestMethod("GET");return conn;}}

定义线程Pool

public class DownloadFileWithThreadPool {public void getFileWithThreadPool(String urlLocation, String filePath, int poolLength) throws IOException {ExecutorService threadPool = Executors.newCachedThreadPool();long len = getContentLength(urlLocation);System.out.println(len);for (int i = 0; i < poolLength; i++) {long start = i * len / poolLength;long end = (i + 1) * len / poolLength - 1;if (i == poolLength - 1) {end = len;}System.out.println(start+"---------------"+end);DownloadWithRange download = new DownloadWithRange(urlLocation, filePath, start, end);threadPool.execute(download);}threadPool.shutdown();}public static long getContentLength(String urlLocation) throws IOException {URL url = null;if (urlLocation != null) {url = new URL(urlLocation);}HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setReadTimeout(5000);conn.setRequestMethod("GET");long len = conn.getContentLength();return len;}}

测试下载单个文件

public static void main(String[] args) {Date startDate = new Date();DownloadFileWithThreadPool pool = new DownloadFileWithThreadPool();try {pool.getFileWithThreadPool("http://mpge.5nd.com/2016/2016-11-15/74847/1.mp3", "D:\\1.mp3", 100);} catch (IOException e) {e.printStackTrace();}System.out.println(new Date().getTime() - startDate.getTime());}

测试发现,我目前的网速,下载一个3.6M左右mp3音频文件,使用多线程,下载大概需要800ms左右,而不使用多线程,则需要1600ms以上,有时候甚至3000ms

多文件下载,单文件单线程

/*** @author Nick 带线程池的文件下载类,线程大小10*      文件数少的情况下,体现不大* @version V1.0.0* @Date 2017/8/2 20:43*/
public class FileDownConnManager {private static final Logger logger = LoggerFactory.getLogger(FileDownConnManager.class);private static final FileDownConnManager connManager = new FileDownConnManager();private static ExecutorService executorService = Executors.newFixedThreadPool(10); //10个线程跑public static FileDownConnManager getDefaultManager() {return connManager;}public static byte[] fileDown(final String netURL) throws ExecutionException, InterruptedException {Future<byte[]> future = executorService.submit(new Callable<byte[]>() {@Overridepublic byte[] call() throws Exception {Date date = new Date();URL url;byte[] getData = new byte[0];InputStream is = null;try {url = new URL(netURL);URLConnection connection = url.openConnection();is = connection.getInputStream();getData = readInputStream(is);} catch (IOException e) {logger.error("从URL获得字节流数组失败 " + ExceptionUtils.getMessage(e));} finally {try {is.close();} catch (IOException e) {logger.error("从URL获得字节流数组流释放失败 " + ExceptionUtils.getMessage(e));}}return getData;}});return future.get();}}

测试

@Testpublic void test2() throws ExecutionException, InterruptedException, IOException {long time1 = System.currentTimeMillis();for(int i = 0; i < 15; i++) {byte[] by1 = FileDownConnManager.fileDown("http://mpge.5nd.com/2016/2016-11-15/74847/1.mp3");FileUtils.writeByteArrayToFile(new File("D:\\test2_"+i+".mp3"), by1);}System.out.println(System.currentTimeMillis() - time1);}@Testpublic void test3() throws IOException {long time1 = System.currentTimeMillis();for(int i = 0; i < 15; i++) {byte[] by1 = FileFromUrlUtil.getInputStreamFromUrl("http://mpge.5nd.com/2016/2016-11-15/74847/1.mp3");FileUtils.writeByteArrayToFile(new File("D:\\test3_"+i+".mp3"), by1);}System.out.println(System.currentTimeMillis() - time1);}

结论:同样的文件,测试发现,在一定数量(文件数量大概15)的文件下载的时候,每个文件是3.6M的情况下,使用多线程大概时间是30xxxms,而不实用多线程大概是38xxxms,还是有一定时间上的提升

此处的测试还是会存在一定的误差,因为ExecutorService线程池的创建是需要时间,类的初始化也是需要一定的时间,假如在Web应用中,第一次创建出来了,第二次不需要创建,优势还是稍微能够体现出来!!

Java多线程下载文件相关推荐

  1. java 多线程下载文件并实时计算下载百分比(断点续传)

    多线程下载文件 多线程同时下载文件即:在同一时间内通过多个线程对同一个请求地址发起多个请求,将需要下载的数据分割成多个部分,同时下载,每个线程只负责下载其中的一部分,最后将每一个线程下载的部分组装起来 ...

  2. java 多线程下载文件

    2019独角兽企业重金招聘Python工程师标准>>> 1.基本思路 2.源码 package cn.itcast.download;import java.io.File; imp ...

  3. java多线程下载文件(断点下载、进度展示、网速展示)

    引言 多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销. 多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的. 一个线程可以创建和撤销另一个线程:同一个进程中的多个线程之间可 ...

  4. java线程下载文件_Java多线程下载文件实例详解

    本文实例为大家分享了Java多线程下载文件的具体代码,供大家参考,具体内容如下 import java.io.File; import java.io.InputStream; import java ...

  5. 【Java】网络编程——多线程下载文件

    前言 多线程下载文件,比单线程要快,当然,线程不是越多越好,这和获取的源文件还有和网速有关. 原理:在请求服务器的某个文件时,我们能得到这个文件的大小长度信息,我们就可以下载此长度的某一个片段,来达到 ...

  6. Java实现多线程下载文件

    这是本人在实际开发当中遇到的多线程下载文件并记录下来 public class DownloadUtil {private String pathFile;private String strFile ...

  7. Java多线程下载分析方法

    为什么要多线程下载 俗话说要以终为始,那么我们首先要明确多线程下载的目标是什么,不外乎是为了更快的下载文件.那么问题来了,多线程下载文件相比于单线程是不是更快? 对于这个问题可以看下图. 横坐标是线程 ...

  8. 多线程下载文件实践之旅

    目录 1.使用场景 2.多线程下载原理 3.请求如何分段下载 3.1.需要请求的数据如何分段. 3.2.分段下载的数据如何组装成完整的数据文件. 4.关键代码实现 3.成果展现 4.总结 5.参考文章 ...

  9. Java多线程下载器(简洁版)

    Java多线程下载器 https://github.com/rawchen/JDownloader/archive/refs/heads/master.zip 五一无聊搞出来的,虽然已存在IDM.XD ...

最新文章

  1. FFmpeg中一个线程获取视频流一个线程执行scale测试代码
  2. 在react-native中使用redux框架
  3. 一位大学教师对学生的建议:如何做好研究
  4. 【机器视觉】机器视觉博客汇总
  5. 第12讲:Ajax 的原理和解析
  6. Python sum函数- Python零基础入门教程
  7. 再谈节奏与动力---平淡与枯燥的力量
  8. 的称重在哪里_如何申请条形码,条形码在哪里申请办理
  9. OCS2007R2部署之四部署存档和监控服务器
  10. 运维必读:避免故障、拒绝背锅的 10 大原则!
  11. Linux服务之DNS服务篇
  12. vue 用webpack打包文件名添加版本号
  13. html实现银行卡号输入,Vue中Element-ui 输入银行账号每四位加一个空格的实现代码_飛雲_前端开发者...
  14. 记录origin画图遇到的问题及其软件bug解决
  15. Python自学之分子运动练习题
  16. vivo X Fold和OPPO Find N
  17. imap java 接收_javamail实现邮件接收功能IMap和pop3方式
  18. MFC之图像绘制---高速绘图控件(High-speed Charting Control)应用(二)
  19. oracle 中YYYY-MM-DD HH24:MI:SS的使用
  20. Row size too large ( 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC

热门文章

  1. Python基础(7)——类和对象(一)
  2. niva mysql_Apache+Mysql+Nivacat+windows
  3. 市场调研报告-全球与中国便携式LCR表市场现状及未来发展趋势
  4. 贪心 135. 分发糖果
  5. python实现数据的批量max-min标准化,告别反复的EXCEL操作
  6. 使用 Java 实现 BMI 指数测试
  7. 【经典语录】阿拉斯加金矿的赌注第4季
  8. 笔记本硬盘删除的数据怎么恢复丨顶尖数据恢复丨
  9. 47-Java编程案例七:双色球系统开发
  10. 用商务领航行的webservice发送短信