需求:
多线程统计数据,需求是要将退单单据的单位分组汇总到同一个表中,因为退单的单据数量多,所以根据公司统计的时候会出现巨大的性能问题,计划使用定时任务,但是因为数据量大所以决定在晚上使用多线程方式将数据完成汇总。
处理方法:
使用多线程方法,ExecutorService线程池,CountDownLatch计算器,Future可以异步保存信息,ConcurrentHashMap不会出现多线程问题的map,Callable多线程接口。
实际代码
@Test
public void execute() {
System.out.println("--------------------------------------------------------------------");
Date start = new Date();
//获取key信息
List<String> dwList = queryOrgId();
//启动线程池
ExecutorService executorService = new ThreadPoolExecutor(10, 50, 100, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>());
//设定一个计数器
countDownLatch = new CountDownLatch(dwList.size());
try {
//多线程的hashmap
Map<String, Future<Map<String, Object>>> futures = new ConcurrentHashMap<>();
//对每一个数据进行处理
for (String orgId : dwList) {
Callable callable = new Callable() {
@Override
public Map<String, Object> call() throws Exception {
return getDataAndSendFile(orgId);
}
};
//可以在进行流程时候保存执行结果
Future<Map<String, Object>> future = executorService.submit(callable);
futures.put(orgId, future);
}
//计算器不为零会被阻塞
countDownLatch.await();
Map<String, Map<String, Object>> resultData = new ConcurrentHashMap<>();
Iterator<Map.Entry<String, Future<Map<String, Object>>>> iterator = futures.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Future<Map<String, Object>>> entry = iterator.next();
if (entry.getValue().isDone() && !entry.getValue().isCancelled()) {
resultData.put(entry.getKey(), entry.getValue().get());
}
}
//执行结果
System.out.println(resultData.toString());
} catch (InterruptedException interruptedException) {
} catch (ExecutionException e) {
} finally {
//关闭线程池
executorService.shutdown();
Date end = new Date();
System.out.println("--------------------------------------------------------------------");
System.out.println(end.getTime()-start.getTime());
}
}
/**
* @Description: 自己的业务代码
*/
public Map<String, Object> getDataAndSendFile(String orgId) {
Map<String, Object> map = new ConcurrentHashMap<>();
try {
map.put(orgId,orgId);
//用来衬托业务流程中使用的时间
Thread.sleep(1000);
return map;
} catch (Exception e) {
map.put(orgId, "调用平衡检查接口异常:" + e.getMessage());
} finally {
countDownLatch.countDown();
}
return map;
}
可以看一下写的具体的注释解释,大概就是自己改改线程池的属性和自己业务就可以了。
没有办法,多线程的话,可能会没有顺序可以后续加一个排序,时间大概是20178。
后续写一个没有使用多线程的代码
@Test
public void executes(){
System.out.println("--------------------------------------------------------------------");
Date start = new Date();
List<String> dwList = queryOrgId();
for (int i = 0; i < dwList.size(); i++) {
String s = dwList.get(i);
getDataAndSendFiles(s);
}
Date end = new Date();
System.out.println("--------------------------------------------------------------------");
System.out.println(end.getTime()-start.getTime());
}
/**
* @Description: 自己的业务代码
*/
public Map<String, Object> getDataAndSendFiles(String orgId) {
Map<String, Object> map = new ConcurrentHashMap<>();
try {
map.put(orgId,orgId);
Thread.sleep(1000);
return map;
} catch (Exception e) {
map.put(orgId, "调用平衡检查接口异常:" + e.getMessage());
}
return map;
}
经过代码的对比性能提升是很大的,希望这个例子在我后面多线程使用的起到作用。