3月份的时候有个这样的需求,查询出一个idList,然后再用每个id查询出很多数据,根据这些数据再查询相关数据,数据的量是相当的大,而且项目没有现配的线程池进行使用,万般无奈之下,自己写了个多线程查询库的操作,下面附源码,请广大码友指教:
Set<Map.Entry<String, List<String>>> entries = columnClassIdList.entrySet();
final CyclicBarrier barrier = new CyclicBarrier(entries.size());
for (Map.Entry<String, List<String>> entry : entries) {
new Thread(new Runnable() {
@Override
public void run() {
logger.info("执行线程名称为:" + Thread.currentThread().getName());
try {
PriceColumn dbPriceColumn = priceColumnDao.getColumnByClassId(entry.getKey());
List<PriceItem> dbPriceItemList = priceItemDao.selectItemByColumnId(dbPriceColumn.getId());
ArrayList<PriceItem> priceItems = new ArrayList<>();
for (PriceItem i : dbPriceItemList) {
if (entry.getValue().contains(i.getClassId())) {
priceItems.add(i);
}
}
//设置结束时间
String formDateStr = null;
String toDateStr = null;
if (type == 3) {
formDateStr = startDateStr;
toDateStr = endDateStr;
}
if (type == 1) {
Date startDate = FormatDate.getDateByRecordCycle(Const.JL_DAY, priceItems.get(0).getEndDate());
//时间转化
formDateStr = FormatDate.dateToString(startDate, "yyyy-MM-dd");
toDateStr = FormatDate.dateToString(priceItems.get(0).getEndDate(), "yyyy-MM-dd");
}
//数据组装
List<String> priceItemIds = priceItems.stream().map(m -> m.getId()).collect(Collectors.toList());
Map<String, PriceItem> priceItemsMap = priceItems.stream().collect(Collectors.toMap(m -> m.getId(), m -> m));
//查询开始
List<PriceItemData> priceItemData = priceDataDao.selectHistoryData(entry.getKey(), priceItemIds, formDateStr, toDateStr);
ArrayList<JSONObject> jsonObjects = new ArrayList<>();
priceItemData.forEach(one -> {
PriceItem priceItem = priceItemsMap.get(one.getPriceItemId());
Map<String, DataAttribute> dataAttributeMap = IterUtil.fieldValueMap(priceItem.getDataAttributes(), "id");
JSONObject one4res = new JSONObject();
one4res.put("item_id", Constants.ID_CODE_JG + one.getItemClassId());
try {
one4res.put("province", areaDictDao.getProvinceByShortName(dataAttributeMap.get("30010").getValue()));
} catch (Exception e) {
logger.error(e.getMessage());
}
one4res.put("company_name", dataAttributeMap.get("30011").getValue());
one4res.put("standard", dataAttributeMap.get("30003").getValue());
one4res.put("product_name", getProduct(dataAttributeMap.get("30001")));
one4res.put("spec", dataAttributeMap.get("30002").getValue());
one4res.put("price_type", dataAttributeMap.get("30017").getValue());
one4res.put("price", one.getPrice());
String priceUnit = StrUtil.concat(true, dataAttributeMap.get("30018").getUnitpre(), "/", dataAttributeMap.get("30018").getUnitlat());
priceUnit = StrUtil.removeSuffix(priceUnit, "/");
one4res.put("price_unit", priceUnit);
one4res.put("datadate", one.getDataDate());
one4res.put("remark", one.getRemark());
res.add(one4res);
});
} catch (Exception e) {
logger.error(e.getMessage());
}
try {
barrier.await();//到达屏障
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}).start();
}
barrier.await();//阻塞当前线程直到latch中数值为零才执行
return res;
中间逻辑很多,很复杂的构造返回,我也想写的好点,奈何领导要求这样写,没办法,我接下来把多线程单独搞出来给大家看:
Set<Map.Entry<String, List<String>>> entries = columnClassIdList.entrySet();
final CyclicBarrier barrier = new CyclicBarrier(entries.size());
for (Map.Entry<String, List<String>> entry : entries) {
new Thread(new Runnable() {
@Override
public void run() {
logger.info("执行线程名称为:" + Thread.currentThread().getName());
try {
barrier.await();//到达屏障
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}).start();
}
barrier.await();//阻塞当前线程直到latch中数值为零才执行
return res;
总体思维是在for循环中new线程执行,因为事先知道了for循环的长度,所以栅栏值也确定,然后开始循环,执行线程中的方法,最后不能忘记await()。
认识一下CyclicBarrier
CyclicBarrier适用于这样的情况:你希望创建一组任务,它们并行的执行工作,然后在进行下一步步骤之前等待,直至所有任务都完成,它使得所有的并行任务都将在删栏出列队,因此可以一致的向前移动。
当调用await时 指定的任务运行完后会awiat 直到最后一个线程运行完毕,才继续执行下一步动作。
通俗点讲就是一组线程相互等待,直到临界点。具体可查官方文档
写的不好,请望理解!!