fork/join到底有多强大?废话不多说,直接看栗子吧
public List<VoucherInfoVo> calculationVoucherPay(String modelNo,SingletonScrollBar singletonScrollBar) throws Exception {
CwVoucherModel cwVoucherModel = null;
CwVoucherModelExample exampleModel = new CwVoucherModelExample();
exampleModel.createCriteria().andModelNoEqualTo(modelNo).andIsDeleteEqualTo((short) 0);
;
List<CwVoucherModel> listModel = cwVoucherModelMapper.selectByExample(exampleModel);
if (listModel != null && listModel.size() > 0) {
cwVoucherModel = listModel.get(0);
}
singletonScrollBar.setNode(cwVoucherModel.getModelName());
// 首先找出对应的模板组信息
CwVoucherModelInfoExample example = new CwVoucherModelInfoExample();
example.createCriteria().andModelNoEqualTo(modelNo).andIsDeleteEqualTo((short) 0);
example.setOrderByClause("id asc");
//获取所有的城市编码
Map<String,String> cityCode=ListChangeToMap(cwVoucherCityCodeInfoMapper.findAllCityCode());
// 获取记账日期
List<VoucherResultVo> dueDates = cwVoucherPayResultMapper.getAccountDate();
String[] accountDate = null;
if (dueDates.size() > 0) {
accountDate = TimeUtil.calculateTime(dueDates.get(0).getDueDate());
}else {
return null;
}
List<CwVoucherModelInfo> list = cwVoucherModelInfoMapper.selectByExample(example);
List<VoucherInfoVo> resutList = new ArrayList<VoucherInfoVo>();
int count = 0;// 分录号
if (list != null) {
singletonScrollBar.setTemp(list.size());
ForkJoinPool forkJoinPool = new ForkJoinPool();
CountTaskPay task = new CountTaskPay(accountDate, 0,list.size() - 1, list, count, singletonScrollBar,cityCode);
Future<List<VoucherInfoVo>> future = forkJoinPool.submit(task);
resutList = future.get();
}
// 生成凭证所需bean类 返回
return resutList;
}
这是统计一个凭证信息的,每一个凭证信息都需要去数据库就行sql查询,表的数据大小大概在20W左右,每一个凭证查询的条件至少在 3个以上,要命的是用到了sum,一个凭证模板里面可能包含10000个左右的sql查询合统计,如果在没有用到fork/join这么一个框架去跑的话,我也尝试用一般的for循环去统计,而线程池又不能很好地控制统计每一个sql结果(就是最后我要得到的那个resultList),单独用for去做这件事,我统计了一下,大概用时 10分钟左右,当时就石化了,这么结果怎么能接受,而我也仔细研究过所写的sql,sql语句没有什么问题,关键是查询,当然也不能给整个数据放到内存里面去,这样内存会爆炸的。于是就尝试用fork/join框架来跑整个结果了,结果很让我吃鲸,整个用时1分30秒左右,对于这样一个大数据统计加导出,这个用时还是能接受的。下面再看看fork/join具体是怎么工作的
@SuppressWarnings("serial")
class CountTaskFack extends RecursiveTask<List<VoucherInfoVo>> {
private static final int threshold = 2;// 阈值
private String[] accountDate;
private int start;
private int end;
private int count;
private SingletonScrollBar singletonScrollBar;
private List<CwVoucherModelInfo> listModel;
private Map<String,String> cityCode;
public CountTaskFack(String[] accountDate, int start, int end,
List<CwVoucherModelInfo> list, int count,
SingletonScrollBar singletonScrollBar,Map<String,String> cityCode) {
this.accountDate = accountDate;
this.start = start;
this.end = end;
this.listModel = list;
this.count = count;
this.singletonScrollBar = singletonScrollBar;
this.cityCode=cityCode;
}
@Override
protected List<VoucherInfoVo> compute() {
DecimalFormat df = new DecimalFormat("######0.00");
List<VoucherInfoVo> list = new ArrayList<>();
boolean compute = (end - start) <= threshold;
if (compute) {
for (int i = start; i <= end; i++) {
CwVoucherModelInfo real = listModel.get(i);
singletonScrollBar.setCurrentTask(singletonScrollBar.getCurrentTask() + 1);
singletonScrollBar.setCount(i + 1);
VoucherInfoVo vo = new VoucherInfoVo();
vo.setBusinessAccounting1(VoucherServerUtil.getRealName(real.getAccountingAux1()));
vo.setCode1(VoucherServerUtil.getCode(real.getAccountingAux1(), real, cityCode,""));
vo.setName1(VoucherServerUtil.getName(real.getAccountingAux1(), real,""));
vo.setBusinessAccounting2(VoucherServerUtil.getRealName(real.getAccountingAux2()));
vo.setCode2(VoucherServerUtil.getCode(real.getAccountingAux2(), real, cityCode,""));
vo.setName2(VoucherServerUtil.getName(real.getAccountingAux2(), real,""));
vo.setBusinessAccounting3(VoucherServerUtil.getRealName(real.getAccountingAux3()));
vo.setCode3(VoucherServerUtil.getCode(real.getAccountingAux3(), real, cityCode,""));
vo.setName3(VoucherServerUtil.getName(real.getAccountingAux3(), real,""));
vo.setAccountDate(accountDate[0]);
vo.setAccountingGap(accountDate[2]);
vo.setVoucherNo(accountDate[3]);
vo.setBusinessDate(accountDate[0]);
vo.setAuxiliaryAccountingDate(accountDate[0]);
vo.setExpireDate(accountDate[0]);
vo.setEntryNo(i + 1 + "");
vo.setAbstractInfo(real.getAccountingAbs());
vo.setAuxiliaryAbstractInfo(real.getAccountingAbs());
vo.setCompany(real.getAccountNum());
vo.setSubjectInfo(real.getSubjectNum());
// 然后根据信息进行分组统计
FactAccountVo conditions = getFactSqlConditionResult(real);
if (conditions.getCitys().size() > 0) {
int cityCount = 0;
for (String city : conditions.getCitys()) {
cityCount++;
if (cityCount==conditions.getCitys().size()) {//统计每一次城市循环 增加滚动条准确度
if (Double.valueOf(df.format(((double) (i + 1) / (double) singletonScrollBar.getTemp()) * 100)) >= singletonScrollBar.getPercentage()) {
singletonScrollBar.setPercentage(Double.valueOf(df.format(((double) (i + 1) / (double) singletonScrollBar.getTemp()) * 100)));
}
}
VoucherInfoVo voc = new VoucherInfoVo();
voc.setBusinessAccounting1(VoucherServerUtil.getRealName(real.getAccountingAux1()));
voc.setCode1(VoucherServerUtil.getCode(real.getAccountingAux1(), real, cityCode,city));
voc.setName1(VoucherServerUtil.getName(real.getAccountingAux1(), real,city));
voc.setBusinessAccounting2(VoucherServerUtil.getRealName(real.getAccountingAux2()));
voc.setCode2(VoucherServerUtil.getCode(real.getAccountingAux2(), real, cityCode,city));
voc.setName2(VoucherServerUtil.getName(real.getAccountingAux2(), real,city));
voc.setBusinessAccounting3(VoucherServerUtil.getRealName(real.getAccountingAux3()));
voc.setCode3(VoucherServerUtil.getCode(real.getAccountingAux3(), real, cityCode,city));
voc.setName3(VoucherServerUtil.getName(real.getAccountingAux3(), real,city));
voc.setAccountDate(accountDate[0]);
voc.setBusinessDate(accountDate[0]);
voc.setVoucherNo(accountDate[3]);
voc.setAccountingGap(accountDate[2]);
voc.setAuxiliaryAccountingDate(accountDate[0]);
voc.setExpireDate(accountDate[0]);
voc.setEntryNo(i + 1 + "");
voc.setAbstractInfo(real.getAccountingAbs());
voc.setAuxiliaryAbstractInfo(real.getAccountingAbs());
voc.setCompany(real.getAccountNum());
voc.setSubjectInfo(real.getSubjectNum());
SelectConditionVo record = new SelectConditionVo();
record.setCity(city);
record.setDate(accountDate[4]);
record.setSum(getFactSqlSumResult(real));
record.setFactAccountVo(conditions);
singletonScrollBar.setCurrentNode(JSON.toJSONString(record));
VoucherResultVo result = cwVoucherFactResultMapper.getFactSheet(record);
logger.info("count=" + i + 1 + "城市结果:"
+ JSON.toJSONString(result));
if (result == null|| result.getTotalfee() == null|| result.getTotalfee().equals(new BigDecimal(0))) {
cityCount++;
if (cityCount == conditions.getCitys().size()) {// 如果所有城市都没有统计出来值
// 那么分录号减一
singletonScrollBar.getTaskCount().add(i + 1);
count--;
}
continue;
}
voc.setTotalFee(result == null ? "" : result.getTotalfee() == null ? "" : result.getTotalfee() + "");
if (!StringUtil.checkIsNull(real.getAccountDir())) {
if (real.getAccountDir().equals("借方")) {
voc.setDebtorMoney(result == null ? "": result.getTotalfee() == null ? "": result.getTotalfee() + "");
voc.setDirection("1");
} else {
voc.setDirection("0");
voc.setLenderMoney(result == null ? "": result.getTotalfee() == null ? "": result.getTotalfee() + "");
}
}
list.add(voc);
}
} else {
if (Double.valueOf(df.format(((double) (i + 1) / (double) singletonScrollBar.getTemp()) * 100)) >= singletonScrollBar.getPercentage()) {
singletonScrollBar.setPercentage(Double.valueOf(df.format(((double) (i + 1) / (double) singletonScrollBar.getTemp()) * 100)));
}
SelectConditionVo record = new SelectConditionVo();
record.setSum(getFactSqlSumResult(real));
record.setFactAccountVo(conditions);
record.setDate(accountDate[4]);
singletonScrollBar.setCurrentNode(JSON.toJSONString(record));
VoucherResultVo result = cwVoucherFactResultMapper.getFactSheet(record);
if (result == null|| result.getTotalfee() == null|| result.getTotalfee().equals(new BigDecimal(0))) {
count--;
singletonScrollBar.getTaskCount().add(i + 1);
continue;
}
vo.setTotalFee(result == null ? "" : result.getTotalfee() == null ? "" : result.getTotalfee() + "");
if (!StringUtil.checkIsNull(real.getAccountDir())) {
if (real.getAccountDir().equals("借方")) {
vo.setDebtorMoney(result == null ? "" : result.getTotalfee() == null ? "" : result.getTotalfee() + "");
vo.setDirection("1");
} else {
vo.setDirection("0");
vo.setLenderMoney(result == null ? "" : result.getTotalfee() == null ? "" : result.getTotalfee() + "");
}
}
list.add(vo);
}
}
} else {
// 任务大于阈值,那么就分裂成两个子任务计算
int middle = (start + end) / 2;
CountTaskFack leftTask = new CountTaskFack(accountDate, start,
middle, listModel, count, singletonScrollBar,cityCode);
CountTaskFack rightTask = new CountTaskFack(accountDate,
middle + 1, end, listModel, count, singletonScrollBar,cityCode);
// 执行子任务
leftTask.fork();
rightTask.fork();
// 等待子任务执行完毕,并得到其结果
List<VoucherInfoVo> left = leftTask.join();
List<VoucherInfoVo> right = rightTask.join();
list.addAll(left);
list.addAll(right);
}
return list;
}
}