1.将list分割并用多线程处理
private SyncRespData dealListByPool(List<Map<String,Object>> list, int nThreads, String uniqueCode) throws Exception {
if (list == null || list.isEmpty()) {
throw new NullPointerException("the collection is null");
}
//计算每个分组存多个数据
int capactiy = list.size() % nThreads > 0 ? list.size() / nThreads : list.size() / nThreads + 1;
if(list.size()<16){
capactiy=1;
}
//进行数据分组(分任务)例如,对包含[a,b,c,d,e]的列表进行分区,分区大小为3,得到[[a,b,c],[d,e]]——一个包含三个和两个元素的两个内部列表的外部列表,所有列表都按原始顺序排列。
List<List<Map<String,Object>>> partions = Lists.partition(list, capactiy);
// 创建一个临时的局部线程池(固定大小)
ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
// 保存结果
List<Future<SyncRespData>> futures = new ArrayList<Future<SyncRespData>>(partions.size());
// 分配任务
for (int i = 0; i < partions.size(); i++) {
// 小任务
SyncToMatrixCallable callTask = new SyncToMatrixCallable(partions.get(i),uniqueCode);
//同步执行多个小任务
futures.add(executorService.submit(callTask));
}
// 关闭线程池
executorService.shutdown();
// 合并
List<Map<String,Object>> result = new ArrayList<Map<String,Object>>();
int ignoreCount=0;
int insertCount=0;
int updateCount=0;
for (Future<SyncRespData> future : futures) {
try {
// 合并
SyncRespData syncRespData = future.get();
result.addAll(syncRespData.getData());
ignoreCount = ignoreCount + syncRespData.getIgnoreCount();
insertCount = insertCount + syncRespData.getInsertCount();
updateCount = updateCount + syncRespData.getUpdateCount();
log.info("不同线程插入总数据条数:{}",JSON.toJSONString(syncRespData));
} catch (Exception e) {
log.info("执行定时任务异常:{}",e.getMessage());
throw new Exception("执行定时任务异常:"+JSON.toJSONString(e.getMessage()),e);
}
}
log.info("主线程结束");
SyncRespData build = SyncRespData.builder().data(result).ignoreCount(ignoreCount).insertCount(insertCount).updateCount(updateCount).build();
return build;
}
2.多线程实际执行的类
private class SyncToMatrixCallable implements Callable<SyncRespData> {
private final List<Map<String,Object>> list;
private final String uniqueCode;
private final ReentrantLock lock = new ReentrantLock();
private SyncToMatrixCallable(List<Map<String, Object>> list, String uniqueCode) {
this.list = list;
this.uniqueCode = uniqueCode;
}
@Override
public SyncRespData call() throws Exception {
// 标记子线程开始
log.info(Thread.currentThread().getName() + " Callable 子线程开始...");
//结果存储
List<Map<String,Object>> resultList = new ArrayList<>();
int ignoreCount = 0;
int insertCount = 0;
int updateCount = 0;
// 业务逻辑处理
for (Map<String, Object> objectMap : list) {
lock.lock();
try {
List<Map<String, Object>> save = save(data);
resultList.addAll(save);
}catch (Exception e){
throw new Exception("数据处理失败:"+JSON.toJSONString(e.getMessage()),e);
}finally {
lock.unlock();
}
}
// 标记子线程结束
log.info(Thread.currentThread().getName() + " Callable 子线程结束...");
return SyncRespData.builder().data(resultList).ignoreCount(ignoreCount).insertCount(insertCount).updateCount(updateCount).build();
}
}
调用多线程代码
SyncRespData syncRespData = dealListByPool(list, 16, uniqueCode);
以上就是对已获取到的list数据量很大时,先分割大小然后使用多线程入库,由于list中可能存在相同的数据,这时需要达到第一条数据新增,第二条数据更新的效果,使用了ReentrantLock,保证的数据的一致性。
如果不使用ReentrantLock保证数据一致性,还可以使用CopyOnWriteArrayList,使用方法如下:
final CopyOnWriteArrayList<Map<String, Object>> list = new CopyOnWriteArrayList<>(data);
SyncRespData syncRespData = dealListByPool(list, 16, transferObject, fieldMap, rule, uniqueCode);
对比上述两种保证多线程数据一致性的方法,使用ReentrantLock的效率稍微高点。