项目场景:
简述项目相关背景:
例如:获取大量数据并处理,生成execl文件导出
问题描述:
5W条数据处理后生成execl文件需要6个小时,效率慢 APP 中接收数据代码:@Override
public void run() {
bytes = mmInStream.read(buffer);
mHandler.obtainMessage(READ_DATA, bytes, -1, buffer).sendToTarget();
}
原因分析:
数据量太多
解决方案:
使用多线程批量处理数据,下面是线程类,直接复制即可
package com.wwhl.cms.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* @param <H> 为被处理的数据类型
* @param <T>返回数据类型
*/
public abstract class MultiThread<H,T>{
private final ExecutorService exec; //线程池
private final BlockingQueue<Future<T>> queue = new LinkedBlockingQueue<>();
private final CountDownLatch startLock = new CountDownLatch(1); //启动门,当所有线程就绪时调用countDown
private final CountDownLatch endLock; //结束门
private final List<H> listData;//被处理的数据
/**
* @param list list.size()为多少个线程处理,list里面的H为被处理的数据
*/
public MultiThread(List<H> list){
if(list!=null&&list.size()>0){
this.listData = list;
exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); //创建线程池,线程池共有nThread个线程
endLock = new CountDownLatch(list.size()); //设置结束门计数器,当一个线程结束时调用countDown
}else{
listData = null;
exec = null;
endLock = null;
}
}
/**
*
* @return 获取每个线程处理结速的数组
* @throws InterruptedException
* @throws ExecutionException
*/
public List<T> getResult() throws InterruptedException, ExecutionException{
List<T> resultList = new ArrayList<>();
if(listData!=null&&listData.size()>0){
int nThread = listData.size(); //线程数量,可根据系统性能自定义线程数
for(int i = 0; i < nThread; i++){
H data = listData.get(i);
Future<T> future = exec.submit(new Task(i,data){
@Override
public T execute(int currentThread,H data) {
return outExecute(currentThread,data);
}
}); //将任务提交到线程池
queue.add(future); //将Future实例添加至队列
}
startLock.countDown(); //所有任务添加完毕,启动门计数器减1,这时计数器为0,所有添加的任务开始执行
endLock.await(); //主线程阻塞,直到所有线程执行完成
for(Future<T> future : queue) {
resultList.add(future.get());
}
exec.shutdown(); //关闭线程池
}
return resultList;
}
/**
* 每一个线程执行的功能,需要调用者来实现
* @param currentThread 线程号
* @param data 每个线程被处理的数据
* @return T返回对象
*/
public abstract T outExecute(int currentThread,H data);
/**
* 线程类
*/
private abstract class Task implements Callable<T>{
private int currentThread;//当前线程号
private H data;
public Task(int currentThread,H data){
this.currentThread=currentThread;
this.data=data;
}
@Override
public T call() throws Exception {
startLock.await(); //线程启动后调用await,当前线程阻塞,只有启动门计数器为0时当前线程才会往下执行
T t =null;
try{
t = execute(currentThread,data);
}finally{
endLock.countDown(); //线程执行完毕,结束门计数器减1
}
return t;
}
/**
* 每一个线程执行的功能
* @param currentThread 线程号
* @param data 每个线程被处理的数据
* @return T返回对象
*/
public abstract T execute(int currentThread,H data);
}
}
使用多线程批量处理数据使用场景:
/**
* 分割list集合
*
* @param dataList
* @return
*/
public List<Card> subList(List<Card> dataList) {
List<Card> resultlist = new ArrayList<>();//存放批量数据处理的总结果集
if (null != dataList && dataList.size() > 0) {
int pointsDataLimit = 10;//限制条数 10条一批
Integer size = dataList.size();
//判断是否有必要分批
if (pointsDataLimit < size) {//大于10条
int part = size / pointsDataLimit;//分批数
for (int i = 0; i < part; i++) {
List<Card> listPage = dataList.subList(0, pointsDataLimit); //10条数据
Integer start = cardlist.size();//10条数据在总结果集的开始下标
cardlist = testTime(listPage, resultlist );//返回拼接后的总结果集
Integer end = resultlist .size();//10条数据在总结果集的结束下标
for (i = start; i < end; i++) {
//对总数据集的10条数据进行业务处理
}
//剔除已经处理过的10条数据
dataList.subList(0, pointsDataLimit).clear();
}
if (!dataList.isEmpty()) {//小于10条
cardlist = testTime(dataList, cardlist);//处理最后的数据
}
} else {
}
}
return resultlist ;
}
/**
* 多线程处理批量数据
*
* @param splitList 处理数据
* @param cardlist 处理后总数据
*
* @return
*/
public List<Card> testTime(List<Card> splitList, List<Card> cardlistr) {
List<Card> list = null;
try {
MultiThread<Card, Card> multiThread = new MultiThread<Card, Card>(splitList) {
@Override
public Card outExecute(int currentThread, Card data) {
//业务处理
/* String iccid = data.getIccid();
String allOrder = cardServerService.findAllOrder(iccid);
String allFlow = cardServerService.allFlowByiccid(iccid);
String allUseFlow = cardServerService.allUseFlowByiccid(iccid);
Card card = cardMapper.findByIccid(iccid);
String monthFlow = card.getMonthFlow();
data.setMonthFlow(monthFlow);
data.setAllOrder(allOrder);
data.setAllFlow(allFlow);
data.setAllUseFlow(allUseFlow);
return data;*/
//业务处理end
}
};
list = multiThread.getResult();//返回结果
for (Card ccar : list) {
cardlist.add(ccar);//批量数据遍历放入总结果
}
} catch (Exception e) {
e.printStackTrace();
}
return cardlist;
}
Card实体
/**
* 卡实体类
*/
public class Card {
/**
* 主键id
*/
private Long id;
/**
* 卡号
*/
private String cardNum;
}