mysql 线程池 下载_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 ? 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 < pageNum; index++) {

int start = index * DOWNLOAD_THREAD_NUM;

int last = getLastNum(size, start + DOWNLOAD_THREAD_NUM);

final CountDownLatch latch = new CountDownLatch(last - start);

// 获取列表子集

List 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 ? size : index;

}

/**

* 获取划分页面数量

*

* @param size

* 列表长度

* @return int

*/

private static int getPageNum(int size) {

int tmp = size / DOWNLOAD_THREAD_NUM;

return size % DOWNLOAD_THREAD_NUM == 0 ? 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 < times; index++) {

DownloadUtil.batch(resMap);

}

}

}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/433024.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sqlite3 编译问题

sqlite3用到libpthread和libdl因此要链接这两个库 假如先把sqlite3.c编译成sqlite3.o或者libsqlite3.a g -lm -lpthread -ldl -o 目标 main.o sqlite3.o 或者 g -lm -lpthread -ldl -lsqlite3 -o 目标 main.o sqlite3.o 都会报链接错误&#xff0c;找不到pthread和dl里面的…

从零开始学习Hadoop--第2章 第一个MapReduce程序

1.Hadoop从头说 1.1 Google是一家做搜索的公司 做搜索是技术难度很高的活。首先要存储很多的数据&#xff0c;要把全球的大部分网页都抓下来&#xff0c;可想而知存储量有多大。然后&#xff0c;要能快速检索网页&#xff0c;用户输入几个关键词找资料&#xff0c;越快越好&…

mysql可以使用sqlplus么_使用sqlplus

1. 执行一个SQL脚本文件SQL>start file_nameSQL> file_name可以将多条sql语句保存在一个文本文件中&#xff0c;这样当要执行这个文件中的所有的sql语句时&#xff0c;用上面的任一命令即可.等于start命令&#xff0c;用来运行一个sql脚本文件命令调用当前目录下的&#…

CPU8085 8086名字的由来

为什么CPU叫8085呢&#xff1f; 8085这个名字的由来还是很有逻辑的&#xff1a;The naming of microprocessor indicates historical facts blended with technology improvements.1)The microprocessor came in the late 70s(1976).This was close to 80.so from here 1ST …

Daily Scrum 10.29

时间越来越紧迫&#xff0c;不过大家逐渐进入了状态。虽然在有些问题上大家意见有些不同&#xff0c;但是最终还都是为着团队着想&#xff0c;很好地达成一致了。 MemberToday’s Task Tomorrow’s Task李孟 task615 测试(活动) task571 完成daily scrum 10.29撰文 task615 测试…

python中list index out of range_Python知识精解:str split()方法

描述split()函数是Python字符串函数。split() 通过指定分隔符对字符串进行切片。如果指定了整型参数num&#xff0c;则仅分隔num 1个子字符串&#xff08;即分割num次&#xff09;。使用split()函数将字符串分割后&#xff0c;返回的是一个列表&#xff0c;列表中存储着分割后…

ashx连接mysql_对C#中的web访问mysql数据库的一些知识点进行了整理归纳总结

基本对比使用方式使用场合优缺点是否需要安装需要的dll网址引用方式程序内引用程序初期确定使用MySql&#xff0c;前期添加引用大多数情况下使用在类文件内&#xff0c;多数使用于aspx&#xff0c;ashx等带有后置代码的类文件中可以安装&#xff0c;也可以直接引用dll 多数情况…

mysql -b -e_MySQL 的B+树索引.

一、B树索引概述索引是应用程序设计和开发的一个重要方面。若索引太多&#xff0c;应用程序的性能可能会受到影响(需维护索引的结构和数据)&#xff1b;而索引太少&#xff0c;对查询性能又会产生影响。二叉树&#xff0c;左子树的键值总是小于根的键值&#xff0c;右子树的键值…

mysql 5.7 api 中文_mysql5.7怎么解决中文

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云数据库专家保驾护航&#xff0c;为用户…

mysql卸载完环境变量还有_MySql完全卸载

这篇文章为转载本博客内容均摘自其他博客&#xff0c;由我整合并且将内容更改的更为详细&#xff0c;方便自己以后观看&#xff0c;也方便各位同学学习&#xff0c;少踩一些坑1.首先我们看一下如何卸载(1)停掉MySql在Windows的服务&#xff1a;开始—> 运行—> services.…

Effective Java学习笔记之第5条 避免创建不必要的对象

第5条 避免创建不必要的对象 一般来说&#xff0c;最好能重用对象而不是在每次需要的时候就创建一个相同功能的对象。 反面例子&#xff1a; String s new String("stringette"); // DONT DO THIS! 对于同时提供了静态工厂方法和构造器都不可变类&#xff0c;通常可…

C_C++变量命名规则

变量命名规则是为了增强代码的可读性和容易维护性。以下为C必须遵守的变量命名规则&#xff1a; 1、 变量名只能是字母&#xff08;A-Z&#xff0c;a-z&#xff09;和数字&#xff08;0-9&#xff09;或者下划线&#xff08;_&#xff09;组成。 2、 第一个字母必须是字母或者下…

pycharm怎么编写python代码_如何设置PyCharm中的Python代码模版(推荐)

在MacOs运行的PyCharm中&#xff0c;执行python文件&#xff0c;如果不指定python文件字符编码会报错&#xff1a;SyntaxError: Non-ASCII character \xe6 in file /Users/yuchao/PycharmProjects/oldboy_python/python_lesson/模块与包/spam.py on line 6,but no encoding dec…

转载——开阔自己的视野,勇敢的接触新知识

在我们公司有buddy制度。每个新员工都会被分配给一个有经验的员工。老员工会在新员工6个月的试用期内给予各种各样的帮助。前几天我被分配到一个新buddy。在和他一起聊天的过程中&#xff0c;明显感觉到他有一些忧虑。“我以前主要做的是c&#xff0c;没做过java&#xff0c;怎…

select与pselect的信号屏蔽

pselect() 函数的原型是&#xff1a;int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask); 它和 select() 函数基本相同&#xff0c;区别在于两个不同的参数&#xff…

vb访问mysql容易死机_VB访问MySQL

最近研究的东西中, 有一部分涉及到用VB访问MySQL数据库, 今天研究了一下小有收获, 共享出来供大家参考首先下载MySQL 的 ODBC 驱动, 我下载的是 MySQL ODBC 3.51 withoutinstaller 版, 下载后是一zip包, 随便解压到哪, 然后运行 cmd, 定位路径到解压的目录, 然后运行 install.b…

cookie注入讲解

我们首先还是来看看中网景论坛的最新版本"(CNKBBS2007)中网景论坛2007v5.0 "官方下载地址" http://www.cnetking.com/websys2.asp?id26"发布时间是2007-06-06,打开系统的源代码后,在"user_RxMsg_detail.asp"文件中,有如下代码:<!--#include …

sigprocmask 阻塞进程

本系列文章由muge0913编写&#xff0c;转载请注明出处&#xff1a;http://blog.csdn.net/muge0913/article/details/7334771 1、有时候不希望在接到信号时就立即停止当前执行&#xff0c;去处理信号&#xff0c;同时也不希望忽略该信号&#xff0c;而是延时一段时间去调用信号处…

python ftp 设置代理_用Python搭建一个简单的代理池

def get_user_agent():随机获取一个用户代理user_agents["Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)","Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET …