用户每周需要上传一个很大的文件,交给后台解析。保存数据。
得到上传的数据,开启线程调用service层方法,同时service添加 synchronized ,在service层中使用线程池对数据进行异步操作,提升数据处理能力
controller层代码(简化)
public ResultCustom import(MultipartFile file) {
if (file == null) {
return ResultCustom.error(500, "导入文件不能为空!");
}
String filename = file.getOriginalFilename();
String type = StrUtil.isBlank(filename) ? "" : filename.substring(filename.lastIndexOf("."));
if (!StrUtil.equalsAny(type, ".xlsx", ".xls")) {
return ResultCustom.error(500, "上传文件格式错误!");
}
// 解析文件放到service层会出现异常,所以在controller层解析把数据传到service
InputStream inputStream;
try {
inputStream = file.getInputStream();
} catch (Exception e) {
return ResultCustom.error(500, e.getMessage());
}
ExcelReader reader = ExcelUtil.getReader(inputStream, 0); //指定输入流和sheet
List<Map<String, Object>> dataMap = reader.readAll();
// 保存处理进度
BImprotProgress bImprotProgress = new BImprotProgress();
bImprotProgress.setFileName(filename); // 文件名
bImprotProgress.setImportTime(LocalDateTime.now()); // 导入时间
bImprotProgress.setCreateUser(XXXXXX); // 导入人
bImprotProgress.setImportState(BasicsConstant.IMPORT_STATE_1); // 导入状态
if (!improtProgressService.save(bImprotProgress)) {
return ResultCustom.error(500, "处理进度保存失败!");
}
// 开后台线程处理导入数据,返回导入状态
new Thread(() -> XXXService.importy(dataMap, ImprotProgress)).start();
return ResultCustom.message("数据导入成功,正在处理!");
}
@Override
public void importy(List<Map<String, Object>> dataMap, BImprotProgress bImprotProgress) {
// 如果重复上传需要把上次的置为不可用
LambdaUpdateWrapper<XXXXX> update = Wrappers.lambdaUpdate();
update.set(XXXX::getIsDelete, BasicsConstant.ISDELETE_1);
XXXMapper.update(null, update);
bImprotProgress.setTotalSize(dataMap.size()); // 总数据量
bImprotProgress.setProgress("0.00%"); // 进度
bImprotProgress.setImportState(BasicsConstant.IMPORT_STATE_2);// 处理中状态
bImprotProgressMapper.updateById(bImprotProgress);
// 开10个线程处理数据,加上主线程等待,计数器设置为11
final CyclicBarrier cyclicBarrier = new CyclicBarrier(11);
// 定义任务线程池,核心线程为10个,最大线程数为15
final ExecutorService executorService = ThreadUtil.newExecutor(10, 15);
// 分页开始,第一页
AtomicInteger atomicLong = new AtomicInteger(1);
// 每页数量
int imit = 100;
int maxThread = 10;
LocalDateTime start = LocalDateTime.now(); // 开始时间
try {
while (true) {
int andIncrement = atomicLong.getAndIncrement();
int basics = (andIncrement - 1) * imit * maxThread;
if ((basics + imit * maxThread) > dataMap.size()) {
// 最后一次的数据了
handleData(dataMap, basics, dataMap.size(), calendarWeek);
break;// 处理完直接跳出
}
for (int i = 0; i < maxThread; i++) {
int pages = i;
executorService.execute(() -> { // 多线程执行
handleData(dataMap, basics + pages * imit, basics + (pages + 1) * imit, calendarWeekfinal);
try {
cyclicBarrier.await(); // 作业完成到达屏障
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
});
}
// 等待所有子线程到达屏障
try {
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
// 当前处理的数量
bImprotProgress.setProgress(NumberUtil.mul(NumberUtil.div(imit * maxThread * andIncrement, dataMap.size(), 2), 100) + "%");
bImprotProgressMapper.updateById(bImprotProgress);
log.info(StrUtil.format("====> 执行完了第{} 次", andIncrement));
}
// 处理成功
bImprotProgress.setProgress("100%");
bImprotProgress.setImportState(BasicsConstant.IMPORT_STATE_3);
bImprotProgress.setCompleteTime(LocalDateTime.now());
bImprotProgressMapper.updateById(bImprotProgress);
} catch (Exception e) {
e.printStackTrace();
bImprotProgress.setImportState(BasicsConstant.IMPORT_STATE_4);
bImprotProgressMapper.updateById(bImprotProgress);
}
LocalDateTime end = LocalDateTime.now();// 结束时间
Duration between = LocalDateTimeUtil.between(start, end);
executorService.shutdown();
String sta = LocalDateTimeUtil.format(start, DatePattern.NORM_DATETIME_PATTERN);
String en = LocalDateTimeUtil.format(end, DatePattern.NORM_DATETIME_PATTERN);
String format = StrUtil.format("开始时间 : {} ,结束时间 : {} ,执行时间 :{}分钟", sta, en, between.toMinutes());
log.info(format);
}
/**
* 数据处理
*
* @param dataMap 数据集合
* @param begin 处理开始下标
* @param end 处理结束下标
*/
private void handleData(List<Map<String, Object>> dataMap, int begin, int end) {
String licenseId;
Integer defnull = 0;
for (int i = begin; i < end; i++) {
Map<String, Object> map = dataMap.get(i);
Set<String> key = map.keySet();
// 根据自己业务定义长度集合,避免出现扩容,影响性能
List<XXX> list = new ArrayList<>(300);
for (String str : key) {
// 业务处理
XXXX
XXXX
list.add(XXX);
}
saveBatch(list, 50);
list.clear();
}
}
private static final Lock LOCK = new ReentrantLock();
public ResultCustom import(MultipartFile file) {
if (file == null) {
return ResultCustom.error(500, "导入文件不能为空!");
}
String filename = file.getOriginalFilename();
String type = StrUtil.isBlank(filename) ? "" : filename.substring(filename.lastIndexOf("."));
if (!StrUtil.equalsAny(type, ".xlsx", ".xls")) {
return ResultCustom.error(500, "上传文件格式错误!");
}
// 是否可以获取锁
if (!LOCK.tryLock()) {
return ResultCustom.error(500, "存在正在处理的文件,上传失败!");
}
// 解析文件放到service层会出现异常,所以在controller层解析把数据传到service
InputStream inputStream;
try {
inputStream = file.getInputStream();
} catch (Exception e) {
LOCK.unlock(); // 解锁
return ResultCustom.error(500, e.getMessage());
}
ExcelReader reader = ExcelUtil.getReader(inputStream, 0); //指定输入流和sheet
List<Map<String, Object>> dataMap = reader.readAll();
// 保存处理进度
BImprotProgress bImprotProgress = new BImprotProgress();
bImprotProgress.setFileName(filename); // 文件名
bImprotProgress.setImportTime(LocalDateTime.now()); // 导入时间
bImprotProgress.setCreateUser(XXXXXX); // 导入人
bImprotProgress.setImportState(BasicsConstant.IMPORT_STATE_1); // 导入状态
if (!improtProgressService.save(bImprotProgress)) {
LOCK.unlock(); // 解锁
return ResultCustom.error(500, "处理进度保存失败!");
}
// 开后台线程处理导入数据,返回导入状态
new Thread(() -> {
try {
ibLaunchStrategyService.importLaunchStrategy(dataMap, bImprotProgress);
} catch (Exception e) {
log.error("数据处理失败" + e.getMessage());
e.printStackTrace();
} finally {
// 解锁
LOCK.unlock();
}
}).start();
return ResultCustom.message("数据导入成功,正在处理!");
}
private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger();
public ResultCustom import(MultipartFile file) {
if (file == null) {
return ResultCustom.error(500, "导入文件不能为空!");
}
String filename = file.getOriginalFilename();
String type = StrUtil.isBlank(filename) ? "" : filename.substring(filename.lastIndexOf("."));
if (!StrUtil.equalsAny(type, ".xlsx", ".xls")) {
return ResultCustom.error(500, "上传文件格式错误!");
}
int lock = ATOMIC_INTEGER.getAndIncrement();
// 是否可以获取锁
if (lock != 0) {
return ResultCustom.error(500, "存在正在处理的文件,上传失败!");
}
// 解析文件放到service层会出现异常,所以在controller层解析把数据传到service
InputStream inputStream;
try {
inputStream = file.getInputStream();
} catch (Exception e) {
// 重置变量,下次上传执行处理操作
atomicIntegerReset();
return ResultCustom.error(500, e.getMessage());
}
ExcelReader reader = ExcelUtil.getReader(inputStream, 0); //指定输入流和sheet
List<Map<String, Object>> dataMap = reader.readAll();
// 保存处理进度
BImprotProgress bImprotProgress = new BImprotProgress();
bImprotProgress.setFileName(filename); // 文件名
bImprotProgress.setImportTime(LocalDateTime.now()); // 导入时间
bImprotProgress.setCreateUser(XXXXXX); // 导入人
bImprotProgress.setImportState(BasicsConstant.IMPORT_STATE_1); // 导入状态
if (!improtProgressService.save(bImprotProgress)) {
// 重置变量,下次上传执行处理操作
atomicIntegerReset();
return ResultCustom.error(500, "处理进度保存失败!");
}
// 开后台线程处理导入数据,返回导入状态
new Thread(() -> {
try {
ibLaunchStrategyService.importLaunchStrategy(dataMap, bImprotProgress);
} catch (Exception e) {
log.error("数据处理失败" + e.getMessage());
e.printStackTrace();
} finally {
// 重置变量,下次上传执行处理操作
atomicIntegerReset();
}
}).start();
return ResultCustom.message("数据导入成功,正在处理!");
}
// 解锁操作
private void atomicIntegerReset() {
int current;
int next = 0;
do {
// 获取原子操作类的值,替换为初始0值
current = ATOMIC_INTEGER.get();
} while (!ATOMIC_INTEGER.compareAndSet(current, next));
}