-
2020-12-02 20:44:50
异常原因
你好! 由于业务需要,多本书的图片会通过本地服务上传至服务器,在一次大批量上传10本以上书籍的时候发现某几本书缺少几张图片。经过排查 ,发现是多线程的问题。改用线程池后仍然无效。
限制贴上部分代码代码
加入同步关键字和睡眠机制仍然无效,加入线程池也无效。
List<Page> pageList = new Vector<>(); CountDownLatch countDownLatch = new CountDownLatch(fileNameList.size()); int count = 0; for (String fileName : fileNameList) { ++count; log.info("本次上传的是第" + count + "张图片,图片名称为===> " + fileName); uploadExecutor.submit(() -> { BufferedImage bufferedImage = null; try { UploadResult uploadResult = null; for (int i = 0; i < 10; i++) { //上传代码省略 if (uploadResult != null) break; } if (uploadResult == null || StringUtils.isEmpty(uploadResult.getUrl()) || uploadResult.getUrl().contains("error")) { log.info("文件" + fileName + "上传失败"); } bufferedImage = ImageIO.read(new File(folder + "/" + fileName)); int width = bufferedImage.getWidth(); int height = bufferedImage.getHeight(); Page page = new Page(); 省略 page.setPageName(fileName); log.info("图片==> " + fileName + " 成功上传,成功地址为==> " + page.getPageUrl()); pageList.add(page); } catch (Exception e) { log.info("上传失败,原因为===》" + e.getMessage()); log.error("上传图片异常:" + e.getMessage()); } finally { if (bufferedImage != null) { bufferedImage.flush(); } countDownLatch.countDown(); } }); try { //休眠50毫秒 Thread.sleep(50L); } catch (InterruptedException e) { e.printStackTrace(); } } try { countDownLatch.await(); } catch (InterruptedException e) { log.error("锁失败"); }
最后排查出来是这一行代码的问题
bufferedImage = ImageIO.read(new File(folder + “/” + fileName));
这个ImageIO类是线程不安全的,过了这一行值就乱了。
最后加入判断,如果上传成功的数量和需要上传的数量不符合,线程就睡眠一秒,继续重试。
最后终于解决了,真是天坑啊。
但是任然不知道这个IO为啥不报错,异常处理的日志没有打印出来更多相关内容 -
多线程上传图片(windows到服务器以及服务器到外部存储系统)
2021-08-19 22:25:41设计思路:队列+多线程 其他方式:redis队列或者mq方式实现,主体思路消费队列 maven依赖 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId&...场景:从磁盘某个地方获取文件然后上传到服务器,或者从服务器上传到外部系统
考虑因素:网络因素,主要是网络带宽(实际环境遇到过,因为服务部署在不同省份)
单线程: 按一秒一张每天传递:24*60*60*N(N为机器数); 服务端带宽大的情况下配置为多线程
具体QPS设计,需要结合网络情况
另外考虑到windows电脑做成服务启动应用,具体可以参考github的项目:Releases · winsw/winsw · GitHubA wrapper executable that can run any executable as a Windows service, in a permissive license. - Releases · winsw/winsw
https://github.com/winsw/winsw/releases
win+R进入:services.msc 可查看最终部署的应用
具体操作见最后面
设计思路:队列+多线程
其他方式:redis队列或者mq方式实现,主体思路消费队列
需要注意的是:生产者生产的速度控制,在生产和消费之间找到一个对应的平衡点
适用于一个生产者多个消费者模式,主要是在消费瓶颈上
最终实现思路,文章代码待完善(阉割版),实际项目中已实现设计图内容
临时map的作用是把上传文件后将本地文件删除,避免删除不掉本地文件的情况(此处考虑过一段时间得到最终处理方案)
监控中心作用:定期将未从临时map中清除的文件清理掉,防止意外情况,正确情况下不会存在此情况发生
另外:实际项目中,本地到远程服务再到远程服务,中间搭建了一个中继服务
具体可参考模式:本地项目-----中继服务------远程服务器
maven依赖
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency>
工程结构图
1.工具类获取bean
/** * description: 获取bean */ @Component public class SpringBeanUtils implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext context) throws BeansException { applicationContext = context; } /** * 通过beanName获取bean * @param beanName * @return */ public static Object getBean(String beanName){ return applicationContext.getBean(beanName); } public static ApplicationContext getApplicationContext() { return applicationContext; } }
2.静态数据中心
/** * description: */ @Component public class MonitorThread { @Value("${parent_file_path}") private String parent_file_path; @Value("${max_thread}") private int max_thread; @PostConstruct public void init() { MiddleUtils.setParent_file_path(parent_file_path); MiddleUtils.setMax_thread(max_thread); new ImageProducer().start(); new ImageMonitorThread().start(); } }
@Component public class MiddleUtils { private static volatile ConcurrentLinkedQueue<String> CONSUMER_FILE = new ConcurrentLinkedQueue<>(); //文件消费队列 private static volatile ConcurrentHashMap<String, Long> FILE_MAP = new ConcurrentHashMap<>(); //计数器 private static String parent_file_path = null; private static int max_thread = 1; public static int getMax_thread() { return max_thread; } public static void setMax_thread(int max_thread) { MiddleUtils.max_thread = max_thread; } public static ConcurrentLinkedQueue<String> getConsumerFile() { return CONSUMER_FILE; } public static void setConsumerFile(ConcurrentLinkedQueue<String> consumerFile) { CONSUMER_FILE = consumerFile; } public static ConcurrentHashMap<String, Long> getFileMap() { return FILE_MAP; } public static void setFileMap(ConcurrentHashMap<String, Long> fileMap) { FILE_MAP = fileMap; } public static String getParent_file_path() { return parent_file_path; } public static void setParent_file_path(String parent_file_path) { MiddleUtils.parent_file_path = parent_file_path; } }
3.线程池
@Component @Slf4j public class ImageThreadPool { @Value("${max_thread}") private int max_thread; @Bean("imageThread") public ThreadPoolTaskExecutor initImagePool() { ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); threadPoolTaskExecutor.setCorePoolSize(max_thread); threadPoolTaskExecutor.setMaxPoolSize(i * 2); threadPoolTaskExecutor.setQueueCapacity(max_thread * 2); threadPoolTaskExecutor.setThreadNamePrefix("image_pool"); threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); threadPoolTaskExecutor.initialize(); return threadPoolTaskExecutor; } }
4.生产者
@Slf4j public class ImageProducer extends Thread { private static ImageService imageService; @Override public void run() { while (true) { /** * https://www.ip138.com/ascii/ 中文路径转为ASCII码 * 做成windows应用 * https://github.com/winsw/winsw/releases */ getImage(MiddleUtils.getParent_file_path()); } } public void getImage(String filePath) { if (Objects.isNull(filePath)) { log.info("根路径为空"); return; } File file = new File(filePath); File[] files = file.listFiles(); if (files == null || files.length < 1) { return; } for (File f : files) { if (f.isDirectory()) { getImage(f.getAbsolutePath()); } else if (f.isFile()) { /** * 自旋等待 */ while (MiddleUtils.getFileMap().size() > MiddleUtils.getConsumerFile().size()) { try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } /** * 将数据加入到队列中 */ Long aLong = MiddleUtils.getFileMap().get(f.getAbsolutePath()); if (aLong != null) { return; } MiddleUtils.getFileMap().put(f.getAbsolutePath(), System.currentTimeMillis()); if (Objects.isNull(imageService)) { imageService = (ImageService) SpringBeanUtils.getBean("imageService"); } try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } imageService.uploadImage(f.getAbsolutePath()); } } } }
5.消费者(可以将图片转成base64字符串,后端做解密操作完成上传服务端)
@Service @Slf4j public class ImageService { @Async("imageThread") public void uploadImage(String filePath) { log.info(filePath); if (Objects.isNull(filePath)) { return; } try { /** * 具体业务 */ log.info("具体业务逻辑"); } catch (Exception e) { e.printStackTrace(); } finally { MiddleUtils.getFileMap().remove(filePath); } } }
pom文件依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>image_upload</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.6</version> </parent> <packaging>pom</packaging> <modules> <module>image_upload_local</module> <module>image_upload_server</module> </modules> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency> </dependencies> </project>
local端
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>image_upload</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>image_upload_local</artifactId> <packaging>jar</packaging> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <build> <finalName>image_upload_local</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.unique.local.ImageUploadLocal</mainClass> </configuration> </plugin> </plugins> </build> </project>
server端也一样
如果部署windows应用的话可以参考如下做法
1.github上下载对应windows位数的exe文件
Releases · winsw/winsw · GitHub
2.将exe文件名和jar文件名配置一样
原始
修改后
xml文件配置,其中BASE为当前exe文件所在目录
<service>
<!-- ID of the service. It should be unique across the Windows system-->
<id>image_upload_local</id>
<!-- Display name of the service -->
<name>image_upload_local</name>
<!-- Service description -->
<description>image_upload_local upload</description>
<!-- Path to the executable, which should be started -->
<executable>java</executable>
<arguments>-jar %BASE%\image_upload_local.jar --server.port=9002</arguments>
<logpath>%BASE%\logs</logpath></service>
安装:image_upload_local.exe install
更新:先停服务 win+r进入服务右键停止服务
卸载程序:image_upload_local.exe uninstall
C:\Users\haoha\Desktop\新建文件夹 (2)\新建文件夹>image_upload_local.exe install
2021-11-13 21:19:20,382 INFO - Installing service 'image_upload_local (image_upload_local)'...
2021-11-13 21:19:20,406 INFO - Service 'image_upload_local (image_upload_local)' was installed successfully.C:\Users\haoha\Desktop\新建文件夹 (2)\新建文件夹>image_upload_local.exe uninstall
2021-11-13 21:21:37,650 INFO - Uninstalling service 'image_upload_local (image_upload_local)'...
2021-11-13 21:21:37,655 INFO - Service 'image_upload_local (image_upload_local)' was uninstalled successfully.C:\Users\haoha\Desktop\新建文件夹 (2)\新建文件夹>
-
Android多线程文件上传
2018-12-01 06:46:46多线程同时下载文件即:在同一时间内通过多个线程对同一个请求地址发起多个请求,将需要下载的数据分割成多个部分,同时下载,每个线程只负责下载其中的一部分,最后将每一个线程下载的部分组装起来即可。 -
Java多线程之定时任务 以及 SpringBoot多线程实现定时任务——异步任务
2022-03-12 17:59:541. SpringBoot 自定义线程池以及多线程间的异步调用(@Async、@EnableAsync) 2.Java多线程之定时任务 以及 SpringBoot多线程实现定时任务 3.@EnableScheduling 与 @Scheduled -
【java网络编程】用TCP socket实现多线程图片上传
2021-08-22 10:59:52单线程上传服务端:客户端:多线程上传修改服务端:修改客户端 单线程上传 服务端: public static void main(String[] args) { try ( // 创建一个ServerSocket监听8080端口的客户端请求 ServerSocket server = ...单线程上传
服务端:
public static void main(String[] args) { try ( // 创建一个ServerSocket监听8080端口的客户端请求 ServerSocket server = new ServerSocket(8000); // 使用accept()阻塞当前线程,等待客户端请求 Socket socket = server.accept(); // 由Socket获得输入流,并创建缓冲输入流 BufferedInputStream in = new BufferedInputStream(socket.getInputStream()); // 由文件输出流创建缓冲输出流 FileOutputStream out = new FileOutputStream("C:\\Users\\14172\\Pictures\\m66.png")) { // 准备一个缓冲区 byte[] buffer = new byte[1024]; // 首次从Socket读取数据 int len = in.read(buffer); while (len != -1) { // 写入数据到文件 out.write(buffer, 0, len); // 再次从Socket读取数据 len = in.read(buffer); }System.out.println("接收完成!"); } catch (IOException e) { e.printStackTrace(); } }
客户端:
/** * @Author he * @Description 测试Socket上传文件的客户端 * @Date 8.22 **/ public class UdpClient { public static void main(String[] args) { try ( // 向本机的8080端口发出请求 Socket socket = new Socket("127.0.0.1", 8000); // 由Socket获得输出流,并创建缓冲输出流 BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream()); // 创建文件输入流 FileInputStream fin = new FileInputStream("C:\\Users\\14172\\Pictures\\m11.png"); // 由文件输入流创建缓冲输入流 BufferedInputStream in = new BufferedInputStream(fin)) { // 准备一个缓冲区 byte[] buffer = new byte[1024]; // 首次读取文件 int len = in.read(buffer); while (len != -1) { // 数据写入Socket out.write(buffer, 0, len); // 再次读取文件 len = in.read(buffer); } System.out.println("上传成功!"); } catch ( ConnectException e) { System.out.println("服务器未启动!"); } catch (IOException e) { e.printStackTrace(); } } }
查看文件:
可以看到自己的目录下已经出现了C:\Users\14172\Pictures\m66.png多线程上传
改成多线程的形式:
修改服务端:
public class isStream { public static void main(String[] args)throws Exception { ServerSocket server = new ServerSocket(8000);// 创建一个ServerSocket监听8080端口的客户端请求 // 使用accept()阻塞当前线程,等待客户端请求 while (true) //(2)开始在这里暂停等待接收客户端的连接,得到一个端到端的Socket管道 { Socket socket = server.accept(); new ServerReadThread(socket).start(); } } class ServerReadThread extends Thread { static int number = 0; private Socket socket; public ServerReadThread(Socket socket) { this.socket = socket; } @Override public void run(){ try( // 由Socket获得输入流,并创建缓冲输入流 BufferedInputStream in = new BufferedInputStream(socket.getInputStream()); // 由文件输出流创建缓冲输出流 FileOutputStream out = new FileOutputStream("C:\\Users\\14172\\socket\\"+number+".png")) { number++; // 准备一个缓冲区 byte[] buffer = new byte[1024]; // 首次从Socket读取数据 int len = in.read(buffer); while (len != -1) { // 写入数据到文件 out.write(buffer, 0, len); // 再次从Socket读取数据 len = in.read(buffer); System.out.println("接收完成!"); } } catch (FileNotFoundException fileNotFoundException) { fileNotFoundException.printStackTrace(); } catch (IOException ioException) { ioException.printStackTrace(); } } }
查看结果:
修改客户端
修改为用户输入图片路径,进行多次上传图片:
public class UdpClient { public static void main(String[] args) throws IOException { int num = 0; Socket socket = new Socket("127.0.0.1", 8000); // 由Socket获得输出流,并创建缓冲输出流 BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream()); Scanner scanner = new Scanner(System.in); // 创建文件输入流 while (true) { num++; try ( // 向本机的8080端口发出请求 //System.out.println("输入文件路径:"); FileInputStream fin = new FileInputStream(scanner.nextLine()); // 由文件输入流创建缓冲输入流 BufferedInputStream in = new BufferedInputStream(fin)) { // 准备一个缓冲区 byte[] buffer = new byte[1024]; // 首次读取文件 int len = in.read(buffer); while (len != -1) { // 数据写入Socket out.write(buffer, 0, len); // 再次读取文件 len = in.read(buffer); } System.out.println("上传成功!"); } catch (ConnectException e) { System.out.println("服务器未启动!"); } catch (IOException e) { e.printStackTrace(); } if(num == 5) break; } } }
查看目录:
发现一个小问题:已经存在的一样的命名的图片不会覆盖
然后有的图片传过去之后格式会损坏,貌似是jpg转为png命名的时候 -
文件分片多线程上传
2021-03-25 08:42:18前两天有人在群里问文件分片上传如何实现,当时没多想就直接说js对文件进行分片,上传分片,后端接受分片,js判断分片上传...前端代码file.html分片多线程上传--梦中程序员出品#info {width: 400px;height: 200px;}...前两天有人在群里问文件分片上传如何实现,当时没多想就直接说js对文件进行分片,上传分片,后端接受分片,js判断分片上传完成,发起合并请求,后端合并文件即可。后来就用webuploader插件实现了一下,然后他问我可不可以帮他写一个不用插件的分片上传,所以才有了下面的文章。
前端代码
file.html
分片多线程上传--梦中程序员出品#info {
width: 400px;
height: 200px;
}
.percent_bg {
position: relative;
width: 400px;
height: 20px;
border: 1px solid #ccc;
}
.percent {
position: absolute;
width: 0%;
height: 100%;
background: #0b821c;
}
.percent_num {
position: absolute;
width: 100%;
height: 100%;
text-align: center;
}
文件分片多线程上传,上传成功后返回url
选择文件后自动上传
线程数:
1
2
3
5
10
0%// 文件分片信息
var blocksInfo = {
"bufferSize": 512 * 1024, // 512K为一片
"blocks": [], // 所有分片文件
"threadNum": 1, // 上传线程数
"filename": "" // 文件名字
};
// 线程信息
var threadInfo = {
"index": 0, // 准备上传的分片索引
"activeThread": 0, // 几个线程在工作
"sendBlocksNum": 0 // 分片上传完成个数
};
// 选择文件触发change事件
$("#file").change(function () {
var file = document.getElementById("file").files[0];
setBlocksInfo(file); // 设置分片信息
// 启动线程
var realThread = Math.min(blocksInfo.threadNum, blocksInfo.blocks.length); // 如果分片数小于线程则只运行分片数的线程
showInfo("分片完成,分了" + blocksInfo.blocks.length + "片,线程数为:" + realThread);
showInfo("------------");
for (var i = 0;i < realThread;i++) {
threadInfo.activeThread++;
// 应该用js的线程插件来控制线程,我们就不用了,我们知道ajax的异步就是用多线程发送请求的,我们使用ajax来模拟多线程,这块虽然函数是单线程,进入事件队列,但是运行到ajax则是多线程了
startThread(i);
}
});
// 设置分片信息
function setBlocksInfo(file)
{
blocksInfo.threadNum = $("#thread_num").val();
blocksInfo.filename = file.name;
var startByte = endByte = 0;
while (true) {
if (endByte + blocksInfo.bufferSize >= file.size) {
endByte = file.size;
} else {
endByte = startByte + blocksInfo.bufferSize;
}
var block = file.slice(startByte, endByte);
blocksInfo.blocks.push(block);
startByte = endByte;
if (endByte >= file.size) {
break;
}
}
}
// 显示运行信息
function showInfo(info)
{
var msg = $("#info").val() + info + "\r\n";
$("#info").val(msg);
var scrollTop = $("#info")[0].scrollHeight;
$("#info").scrollTop(scrollTop);
}
// 线程运行
function startThread(i)
{
if (threadInfo.index >= blocksInfo.blocks.length) {
showInfo("线程" + i + "结束");
threadInfo.activeThread--;
if (threadInfo.activeThread == 0) {
showInfo("------------");
showInfo("分片上传完成,正在处理分片");
combineBlocks(); // 发起合并分片请求
}
return;
}
uploadBlock(i, threadInfo.index); // 使用指定线程上传指定分片
threadInfo.index++; // 准备下一个分片
}
// 上传分片
function uploadBlock(i, index)
{
showInfo("线程" + i + "开始:上传" + index + "分片");
// 组装上传信息,ajax上传文件需要formdata
var fd = new FormData();
fd.append("index", index); // 上传分片序号
fd.append("file", blocksInfo.blocks[index]);
$.ajax({
url: "upload.php",
type: "post",
data: fd,
dataType: "json",
contentType: false, // 文件上传和参数传递请求头和请求体都不一样,ajax设置false就可以
processData: false, // 有文件上传,不对参数序列化
success: function (data) {
threadInfo.sendBlocksNum++; // 设置这个分片已经上传完成
showPercent(); // 上传进度条
showInfo("分片" + index + "上传完成,线程" + i + "即将上传下一个分片");
startThread(i); // 启动线程继续下一个分片上传
}
});
}
// 发起合并分片请求
function combineBlocks()
{
$.ajax({
url: "upload.php",
type: "post",
data: {"act": "combine", "blocks": blocksInfo.blocks.length, "filename": blocksInfo.filename},
dataType: "json",
success: function (data) {
showInfo("分片数据处理完成,任务结束,URL:" + data.url);
}
});
}
// 进度条
function showPercent()
{
var percent = parseInt(threadInfo.sendBlocksNum / blocksInfo.blocks.length * 100);
$(".percent").stop(true, true).animate({"width": percent + "%"}, 10);
$(".percent_num").html(percent + "%");
}
后端代码
upload.php
class Uploader
{
public $tmpPath = __DIR__ . '/tmp/'; // 分片目录
public $filePath = __DIR__ . '/file/'; // 合并分片目录,这俩个目录需手动创建,你也可以使用mkdir创建
public function upload()
{
if (isset($_POST['act']) && $_POST['act'] == 'combine') {
$blocks = $_POST['blocks'];
$filename =time() . $_POST['filename'];
$file = fopen($this->filePath . $filename, 'a+');
for ($i = 0;$i < $_POST['blocks'];$i++) {
$chunkFile = fopen($this->tmpPath . $i, 'r');
fwrite($file, fread($chunkFile, filesize($this->tmpPath . $i)));
fclose($chunkFile);
unlink($this->tmpPath . $i);
}
fclose($file);
$data = [
'url' => "http://" . $_SERVER['HTTP_HOST'] . '/file/' . $filename
];
} else {
$index = $_POST['index']; // 分片索引
move_uploaded_file($_FILES['file']["tmp_name"], $this->tmpPath . $index);
$data = [
'code' => 1
];
}
return json_encode($data);
}
}
echo (new Uploader)->upload();
有疑问可联系QQ305530751
梦中程序员系列教程
-
Java大文件分片上传/多线程上传组件
2021-02-28 14:04:40javaweb上传文件上传文件的jsp中的部分上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求1.通过form表单向后端发送请求Save改进后的代码不需要form标签,直接由控件来实现。开发人员只需要... -
Java基础知识之多线程并行执行上传图片操作
2020-03-30 23:29:07} } } 线程任务: 获得连接的IP、处理发送过来的图片数据等,这些都是每个线程需要执行的任务,所以需放在线程的run( )方法中执行。 public class UploadTask implements Runnable { //规定上传文件的最大大小 ... -
C# 文件上传下载(Excel导入,多线程下载)功能的实现代码
2020-08-29 14:07:42主要介绍了C# 文件上传下载(Excel导入,多线程下载)功能的实现代码,需要的朋友可以参考下 -
java多线程实现下载图片并压缩
2020-08-27 12:29:02主要为大家详细介绍了java多线程实现下载图片并压缩,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 -
多线程大文件分片上传思路分享
2021-04-28 16:03:20NETCore 大文件分片上传多...根据上图可以看出我上传分片的整个思路,如果是同步上传的情况下是没有问题的,如果存在多线程上传,在“判断分片是否全部上传完成”这步会存在问题,当第一个线程进入上传流程时, ... -
JAVA实现TCP多线程上传图片
2019-12-12 19:50:32前段时间学习了JAVA中的网络编程,于是就动手写了一个TCP多线程上传图片至服务器端的实例。以供学习交流,若有BUG,还望多多评论学习交流,共同进步。 一:客户端 package netdemo1; import java.io.... -
Android 使用多线程来做多文件上传Or下载
2017-11-11 16:45:24在Android中当需要上传或者下载多个图片或者文件到手机时...多线程的调度就需要用到线程池了,由于Android是基于java语言实现,所以Android中用到的多线程跟java中的多线程是一样的。下面介绍下java的线程... -
多线程 网络编程 文件上传案例多线程
2021-03-13 03:40:34Day13 多线程3).多线程的好处:提高程序的运行效率,提高用户的体验度。 线程不会因为等待某个资源而进入等待状态创建新的线程:* 定义类继承Thread* 重写方法run* 创建Thread子类的对象* 调用子类对象的方法start()*... -
SpringBoot版本的多线程下载文件,分段下载文件
2020-11-24 13:21:05新鲜出炉的SpringBoot版本的多线程下载文件,可以拿来整合SpringBoot项目或者SSM项目,可直接运行测试!!! -
IOS多线程实现多图片下载(二)
2021-01-04 10:04:57上篇文章给大家介绍了IOS多线程实现多图片下载1,本文继续给大家介绍ios多线程下载图片。 这次是用多线程进行图片的下载与存储,而且考虑到下载失败,占位图片的问题(第一张就是下载失败的图片) 闲话少说,上代码吧... -
java 多线程上传图片,频繁IO,哪种方式优化耗时短些。
2021-03-18 00:33:39现在就是批量处理商品,每个商品都有很多张图片,现在多线程上传使用countDownLatch阻塞等待,有没有更好的优化方式能够多线程上传多张图片然后执行下面的步骤小腊肠 上传图片为啥要后端多线程? 一般不是先上传再... -
Spring boot实现文件上传实例(多文件上传)
2020-08-30 15:14:00本篇文章主要介绍了Spring boot实现文件上传实例(多文件上传),具有一定的参考价值,感兴趣的小伙伴们可以参考一下 -
若依实现文件多线程批量上传案例
2021-12-11 15:59:36若依实现文件多线程批量上传案例 -
FTP多线程上传文件资料
2012-06-15 01:24:13FTP多线程上传文件资料 -
springmvc配置线程池Executor做多线程并发操作的代码实例
2020-08-26 05:59:30今天小编就为大家分享一篇关于springmvc配置线程池Executor做多线程并发操作的代码实例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧 -
ftp多线程上传、下载以及断点续传
2021-06-26 20:49:07/// 异步上传 (多个文件最好用这个方法) 多线程时设置最大连接数 可以保证按队列先入先出去传输 此时不需要设置线程池中线程数量 /// </summary> /// <param name="fullName"></param&... -
京东多线程版易语言源码
2020-11-26 16:19:46京东多线程版易语言源码,易语言版本, 1》支持京东多账号登录,批量下单 2》支持监控有货下单,变价下单,定时抢购,各有各的好,多种方式可供选择; 3》可同时添加多个商品进行抢购; 4》支持多线程同时抢购,... -
flickruper:Flickr CLI 多线程上传器,可以在失败时恢复上传
2021-06-19 17:41:46闪烁Flickr CLI 多线程上传器,可以在失败时恢复上传。 现在 Flickr 为每个人提供 1TB 的空间,将所有原始照片存储在那里非常方便。 该工具有助于一次性将大量文件上传到 Flickr。安装您可以安装 flickruper pip ... -
oss多线程分片上传
2020-09-08 11:42:23今天博主就oss多线程分片上传作个分享。 2. 分片代码 2.1 主线程代码 private static final long EACH_PART_SIZE = 2 * 1024 * 1024; // 创建InitiateMultipartUploadRequest对象 ... -
网络编程——(6)TCP协议——多线程上传图片至服务端
2020-01-20 20:13:35单机版的图片上传太鸡肋,一旦人数过多时,服务就会超时,所以就引入了多线程技术,多个线程处理不同的IP(主机)上传图片的业务。 首先看客户端: public class uploadpicThreadClient { public static void main... -
SpringBoot整合阿里云OSS上传文件,多线程分片上传,普通上传,文件删除
2022-06-14 15:05:20SpringBoot整合阿里云OSS上传文件,多线程分片上传 -
C# Winform 多线程下载
2017-09-14 16:15:50根据博文C# 文件上传下载(Excel导入,多线程下载),用Winform对多线程下载进行了呈现,原文链接:http://www.cnblogs.com/liudiwei/p/6041641.html