线程模型
生产者Provider线程为一,主要进行深搜目录文件;、
消费者Consumer线程多个, 因为RPC服务调用时延较长, 启用多个线程请求服务。
持久化线程Persist 将已经消费的消息存放在writeQueue, 启用一个线程从writeQueue取数据进行持久化到log.pic,这样每次启动压缩的时候,可以避免重复消费。 进而避免同一目录进行多次压缩
api_key.properties 为申请的https://tinypng.com/ 的key ,每个key一个月可以压缩500张, 采用线程名的hashCode对key的个数取模运算,选择所要使用的key。
可扩展性
doCompress方法可以进行任意业务逻辑。只是我的实现是用来压缩图片了。
代码已push到github, 已经打好的jar也已上传。需要的可以clone一下。源码已打入jar包
如何使用
1、下载Compress.jar包
2、maven手动安装jar
mvn install:install-file -DgroupId=com.hearglobal -DartifactId=multi -Dversion=2.0 -Dpackaging=jar -Dfile=C:/Users/cbam/Desktop/Compress.jar
3、公共接口说明:
compress.setApi_key_location("/api_key.properties"); // 指定api_key文件位置 key需要申请 可选设置 默认为项目根路径 如E:/work/{project}/api_key.properties或/work/{project}/api_key.properties
compress.setPic_log_location("/log.pic"); //指定log.pic路径 可选配置 默认为项目根路径 如/work/{project}/log.pic 或 /work/{project}/log.pic
compress.compress("E:/upan/test", "E:/upan/test_bak", 3);//压缩调用 第一个参数为要压缩的目录 第二个参数为 压缩输出目录 第三个参数 启动的线程数
3、程序调用jar示例一
建议指定绝对路径
public static void main(String[] args) throws Exception {
Starter compress = new Starter();
compress.setApi_key_location("/api_key.properties");
compress.setPic_log_location("/log.pic");
compress.compress("E:/upan/test", "E:/upan/test_bak", 3);
}
4、程序调用jar示例二
打开win控制台或 在Linux shell下jar包当前目录 运行如下命令
java -jar Compress.jar E:/upan/test E:/upan/test_bak 3 //压缩调用 第一个参数为要压缩的目录 第二个参数为 压缩输出目录 第三个参数 启动的线程数
运行截图:
注意:此方式无法设置配置文件位置, 故请将文件api_key.properties默认放置在 jar包所在目录
生产者Provider代码:
package com.hearglobal.multi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
/**
* CopyRright (c)2014-2016 Haerbin Hearglobal Co.,Ltd
* Project: tinypngThread
* Comments:
* Author:cbam
* Create Date:2017/3/21
* Modified By:
* Modified Date:
* Modified Reason:
*/
public class Provider implements Callable{
private static final Logger LOGGER = LoggerFactory.getLogger(Consumer.class);
//消息队列
private BlockingQueue messageQueue;
private static LinkedList logList ;
//生产东西来源
private static File src;
/**
* Instantiates a new Provider.
*
*@param messageQueue the message queue
*@param src the src
*/
public Provider(BlockingQueue messageQueue, File src){
this.messageQueue = messageQueue;
this.src = src;
}
public Object call() throws Exception {
try {
load(src);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
} finally {
return true;
}
}
private void load(File src) throws InterruptedException {
LOGGER.info("Provider load src:{}", src.getAbsolutePath());
// 当找到目录时,创建目录
if (src.isDirectory()) {
if(!logList.contains(src.getAbsolutePath())) {
if(!this.messageQueue.offer(src, 2, TimeUnit.SECONDS)) {
System.out.println("目录提交队列失败....");
};
}
File[] files = src.listFiles();
for(File file : files) {
load(file);
}
//当找到文件时
} else if (src.isFile()) {
if(validatePic(src) && !logList.contains(src