热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

java线程池实现批量下载文件

这篇文章主要为大家详细介绍了java线程池实现批量下载文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了java线程池实现批量下载文件的具体代码,供大家参考,具体内容如下

1 创建线程池

package com.cheng.webb.thread;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class ThreadUtil {
 
 /**
   * 创建批量下载线程池
   *
   * @param threadSize 下载线程数
   * @return ExecutorService
   */
  public static ExecutorService buildDownloadBatchThreadPool(int threadSize) {
    int keepAlive = 0;
    String prefix = "download-batch";
    ThreadFactory factory = ThreadUtil.buildThreadFactory(prefix);


    return new ThreadPoolExecutor(threadSize,
        threadSize,
        keepAlive,
        TimeUnit.SECONDS,
        new ArrayBlockingQueue<>(threadSize),
        factory);
  }
  
  /**
   * 创建自定义线程工厂
   *
   * @param prefix 名称前缀
   * @return ThreadFactory
   */
  public static ThreadFactory buildThreadFactory(String prefix) {
    return new CustomThreadFactory(prefix);
  }
  
  
  /**
   * 自定义线程工厂
   */
  public static class CustomThreadFactory implements ThreadFactory {

    private String threadNamePrefix;

    private AtomicInteger counter = new AtomicInteger(1);

    /**
     * 自定义线程工厂
     *
     * @param threadNamePrefix 工厂名称前缀
     */
    CustomThreadFactory(String threadNamePrefix) {
      this.threadNamePrefix = threadNamePrefix;
    }

    @Override
    public Thread newThread(Runnable r) {
      String threadName = threadNamePrefix + "-t" + counter.getAndIncrement();
      return new Thread(r, threadName);
    }
  }

}

2 批量下载文件

package com.cheng.webb.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 文件下载类
 * 
 * @author shucheng
 * @creation 2019年1月30日下午4:41:32
 */
public class DownloadUtil {

 private static Logger logger = LoggerFactory.getLogger(DownloadUtil.class);

 /**
 * 下载线程数
 */
 private static final int DOWNLOAD_THREAD_NUM = 14;

 /**
 * 下载线程池
 */
 private static ExecutorService downloadExecutorService = ThreadUtil
  .buildDownloadBatchThreadPool(DOWNLOAD_THREAD_NUM);

 /**
 * 文件下载
 *
 * @param fileUrl
 *      文件url,如:https://img3.doubanio.com//view//photo//s_ratio_poster//public//p2369390663.webp
 * @param path
 *      存放路径,如: /opt/img/douban/my.webp
 */
 public static void download(String fileUrl, String path) {
 // 判断存储文件夹是否已经存在或者创建成功
 if (!createFolderIfNotExists(path)) {
  logger.error("We can't create folder:{}", getFolder(path));
  return;
 }

 InputStream in = null;
 FileOutputStream out = null;
 try {
  URL url = new URL(fileUrl);
  HttpURLConnection cOnn= (HttpURLConnection) url.openConnection();
  conn.setRequestMethod("GET");
  // 2s
  conn.setConnectTimeout(10000);
  in = conn.getInputStream();

  out = new FileOutputStream(path);

  int len;
  byte[] arr = new byte[1024 * 1000];
  while (-1 != (len = in.read(arr))) {
  out.write(arr, 0, len);
  }
  out.flush();
  conn.disconnect();
 } catch (Exception e) {
  logger.error("Fail to download: {} by {}", fileUrl, e.getMessage());
 } finally {
  try {
  if (null != out) {
   out.close();
  }
  if (null != in) {
   in.close();
  }
  } catch (Exception e) {
  // do nothing
  }
 }
 }

 /**
 * 创建文件夹,如果文件夹已经存在或者创建成功返回true
 *
 * @param path
 *      路径
 * @return boolean
 */
 private static boolean createFolderIfNotExists(String path) {
 String folderName = getFolder(path);
 if (folderName.equals(path)) {
  return true;
 }
 File folder = new File(getFolder(path));
 if (!folder.exists()) {
  synchronized (DownloadUtil.class) {
  if (!folder.exists()) {
   return folder.mkdirs();
  }
  }
 }
 return true;
 }

 /**
 * 获取文件夹
 *
 * @param path
 *      文件路径
 * @return String
 */
 private static String getFolder(String path) {
 int index = path.lastIndexOf("/");
 return -1 != index &#63; path.substring(0, index) : path;
 }

 /**
 * 下载资源
 * 

* issue: 线程池创建过多 *

* 最大批量下载为5,请知悉 * * @param resourceMap * 资源map, key为资源下载url,value为资源存储位置 */ public static void batch(Map resourceMap) { if (resourceMap == null || resourceMap.isEmpty()) { return; } try { List keys = new ArrayList<>(resourceMap.keySet()); int size = keys.size(); int pageNum = getPageNum(size); for (int index = 0; index urlList = keys.subList(start, last); for (String url : urlList) { // 提交任务 Runnable task = new DownloadWorker(latch, url, resourceMap.get(url)); downloadExecutorService.submit(task); } latch.await(); } } catch (Exception e) { logger.error("{}", e); } logger.info("Download resource map is all done"); } /** * 获取最后一个元素 * * @param size * 列表长度 * @param index * 下标 * @return int */ private static int getLastNum(int size, int index) { return index > size &#63; size : index; } /** * 获取划分页面数量 * * @param size * 列表长度 * @return int */ private static int getPageNum(int size) { int tmp = size / DOWNLOAD_THREAD_NUM; return size % DOWNLOAD_THREAD_NUM == 0 &#63; tmp : tmp + 1; } /** * 下载线程 */ static class DownloadWorker implements Runnable { private CountDownLatch latch; private String url; private String path; DownloadWorker(CountDownLatch latch, String url, String path) { this.latch = latch; this.url = url; this.path = path; } @Override public void run() { logger.debug("Start batch:[{}] into: [{}]", url, path); DownloadUtil.download(url, path); logger.debug("Download:[{}] into: [{}] is done", url, path); latch.countDown(); } } }

3 测试批量下载文件

package com.cheng.webb.thread;

import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import com.alibaba.fastjson.JSON;

public class DownLoadTest {
 String json = "{\r\n"
  + " \"http://www.xxx.com/111/123.mp4\":\"myFile/111/123.mp4\",\r\n"
  + " \"http://www.xxx.com/111/124.mp4\":\"myFile/111/124.mp4\",\r\n"
  + " \"http://www.xxx.com/111/125.mp4\":\"myFile/111/125.mp4\"\r\n"
  + "}";

 @SuppressWarnings("unchecked")
 @Test
 public void test() {
 Map map = new HashMap<>();
 Map resMap = JSON.parseObject(json, map.getClass());

 int times = 1;
 for (int index = 0; index 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 深入理解SAP Fiori及其核心概念
    本文详细介绍了SAP Fiori的基本概念、发展历程、核心特性、应用类型、运行环境以及开发工具等,旨在帮助读者全面了解SAP Fiori的技术框架和应用场景。 ... [详细]
  • 本文详细介绍了如何在不同操作系统中设置 Node.js 的环境变量,包括通过命令行、npm 脚本以及直接在代码中设置的方法。 ... [详细]
  • 本文介绍了如何使用 Git 命令来忽略那些已经提交或者从远程仓库拉取但在本地进行了修改的文件,避免这些文件在不必要的时候被再次提交。 ... [详细]
  • 深入解析Keras中的ImageDataGenerator参数
    本文详细探讨了Keras库中ImageDataGenerator类的各项参数及其功能,旨在帮助读者更好地理解和应用数据增强技术,提高模型训练效果。 ... [详细]
  • VSCode中实现大型项目函数跳转的方法
    在处理大型代码项目时,简单的C/C++插件往往无法满足需求。本文介绍如何通过配置GNU Global等工具,在VSCode中实现高效的函数跳转。 ... [详细]
  • 使用EF Core在.Net Core控制台应用中操作SQLite数据库
    本文介绍如何利用Visual Studio 2019和Windows 10环境,通过Entity Framework Core(EF Core)实现对SQLite数据库的读写操作。项目源代码可从百度网盘下载。 ... [详细]
  • 本文详细介绍了如何通过配置 Chrome 和 VS Code 来实现对 Vue 项目的高效调试。步骤包括启用 Chrome 的远程调试功能、安装 VS Code 插件以及正确配置 launch.json 文件。 ... [详细]
  • 微信小程序支付官方参数小程序中代码后端发起支付代码支付回调官方参数文档地址:https:developers.weixin.qq.comminiprogramdeva ... [详细]
  • 择要:Fundebug的JavaScript毛病监控插件同步支撑Vue.js异步毛病监控。Vue.js从降生至今已5年,尤大在本年2月份宣布了严重更新,即Vue2.6。更新包含新增 ... [详细]
  • 面对快应用开发时需要获取摘要值的需求,但官方API并未直接提供相应支持。通过探索发现,利用第三方加密库crypto-js可有效解决此问题。本文将详细介绍如何集成并使用该库来实现摘要值的获取。 ... [详细]
  • 优雅地记录API调用时长
    本文旨在探讨如何高效且优雅地记录API接口的调用时长,通过实际案例和代码示例,帮助开发者理解并实施这一技术,提高系统的可观测性和调试效率。 ... [详细]
  • 探讨如何使用青花瓷抓包工具正确解析GZIP压缩的JSON请求,并寻找替代方案。 ... [详细]
  • 多项目环境下的代码复用策略
    在前端开发中,面对多个并行项目的场景,如何有效地实现代码复用成为了一个重要的议题。本文将探讨一种利用npm包管理来实现跨项目组件共享的方法。 ... [详细]
  • 本文探讨了JavaScript的基本概念,包括其作为解释型、脚本语言的特点,以及它支持的面向对象编程(OOP)原则。重点介绍了封装、继承和多态等OOP特性,并详细解释了如何在JavaScript中创建和使用对象。 ... [详细]
  • VS Code 中 .vscode 文件夹配置详解
    本文介绍了 VS Code 中 .vscode 文件夹下的配置文件及其作用,包括常用的预定义变量和三个关键配置文件:launch.json、tasks.json 和 c_cpp_properties.json。 ... [详细]
author-avatar
陈氏女子2602926065
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有