demand: TMS系统 - 运输管理 - 漏组批次全量扫描数据量过大会造成CPU飙升问题优化

committer: heyu
This commit is contained in:
aike 2025-10-09 18:49:52 +08:00
parent 2c52db5cca
commit f655d26ded

View File

@ -4,7 +4,10 @@ import java.util.*;
import java.util.stream.Collectors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import cn.hutool.core.collection.CollectionUtil;
import com.xdadan.erp.emis.domain.*;
@ -248,6 +251,7 @@ public class EmisTmsSiteBatchMissServiceImpl extends EmisBaseService implements
@Async
@Override
public void autoScanSiteBatch(String lineCode) {
ExecutorService executorService = null;
try {
emisTmsSiteBatchMissMapper.deleteReally(lineCode);
long startTime = System.currentTimeMillis();
@ -272,8 +276,20 @@ public class EmisTmsSiteBatchMissServiceImpl extends EmisBaseService implements
.collect(Collectors.groupingBy(EmisTransPlanRule::getLineCode));
// 创建线程池
int processors = Runtime.getRuntime().availableProcessors();
ExecutorService executorService = Executors.newFixedThreadPool(processors);
int processors = Runtime.getRuntime().availableProcessors() ;
executorService = new ThreadPoolExecutor(
processors/2, // 核心线程数
processors, // 最大线程数
60L, // 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(), // 工作队列
r -> {
Thread t = new Thread(r);
t.setName("emis-scan-" + t.getId());
t.setDaemon(false);
return t;
} // 线程工厂
);
List<Future<List<EmisWaybill>>> futures = new ArrayList<>();
// 先查询所有数据
@ -299,77 +315,49 @@ public class EmisTmsSiteBatchMissServiceImpl extends EmisBaseService implements
}
}
// 关闭线程池
executorService.shutdown();
// // 构建运单号到EmisWaybill的映射
// Map<String, EmisWaybill> waybillMap = allWaybills.stream()
// .collect(Collectors.toMap(EmisWaybill::getBillCode, Function.identity(), (a,
// b) -> a));
//
// allWaybills = allWaybills.stream()
// .filter(wb -> {
// String virtualRemark = wb.getVirtualRemark();
// if (StringUtils.isBlank(virtualRemark)) {
// return true;
// }
// // 解析virtualRemark中的运单号
// String[] relatedNos = virtualRemark.split(",");
// for (String no : relatedNos) {
// EmisWaybill related = waybillMap.get(no.trim());
// if (related != null && Objects.equals(related.getProblemType(), 173)) {
// return false; // 只要有一个关联运单problemType=173,则过滤掉
// }
// }
// return true;
// })
// .collect(Collectors.toList());
//
// allWaybills = allWaybills.stream()
// .filter(wb -> !Objects.equals(wb.getProblemType(), 170))
//// .filter(wb -> !Objects.equals(wb.getSiteBatchStatus(), "1"))
// .collect(Collectors.toList());
//
// totalProcessed = allWaybills.size();
// 按1000条数据分组处理
int batchSize = 1000;
List<List<EmisWaybill>> batches = new ArrayList<>();
for (int i = 0; i < allWaybills.size(); i += pageSize) {
int end = Math.min(i + pageSize, allWaybills.size());
for (int i = 0; i < allWaybills.size(); i += batchSize) {
int end = Math.min(i + batchSize, allWaybills.size());
batches.add(allWaybills.subList(i, end));
}
if (CollectionUtil.isEmpty(batches)) {
log.info("No waybills to process, skip batch processing");
return;
}
// 创建新的线程池处理数据
executorService = Executors.newFixedThreadPool(1);
List<Future<EmisBaseService.ProcessResult>> processFutures = new ArrayList<>();
log.info("Processing {} batches with batch size: {}, total waybills: {}",
batches.size(), batchSize, allWaybills.size());
// 复用现有线程池
List<Future<ProcessResult>> processFutures = new ArrayList<>();
for (List<EmisWaybill> batch : batches) {
processFutures.add(executorService.submit(() -> processWaybillBatch(batch, transPlanRulesByLineCode)));
}
// 收集处理结果
// 添加超时机制,避免长时间阻塞
List<EmisWaybillBatchStatus> allBatchStatus = new ArrayList<>();
List<EmisTmsSiteBatchMiss> allMissRecords = new ArrayList<>();
for (Future<EmisBaseService.ProcessResult> future : processFutures) {
int timeoutMinutes = 10; // 10分钟超时
for (Future<ProcessResult> future : processFutures) {
try {
ProcessResult result = future.get();
ProcessResult result = future.get(timeoutMinutes, TimeUnit.MINUTES);
successCount += result.getSuccessCount();
failCount += result.getFailCount();
failedBillCodes.addAll(result.getFailedBillCodes());
allBatchStatus.addAll(result.getBatchStatusList());
allMissRecords.addAll(result.getMissRecords());
} catch (TimeoutException e) {
log.error("Batch processing timeout after {} minutes", timeoutMinutes);
future.cancel(true); // 取消超时任务
} catch (Exception e) {
log.error("Error processing batch", e);
}
}
// 关闭线程池
executorService.shutdown();
// 全局去重
Map<String, EmisWaybillBatchStatus> batchStatusMap = allBatchStatus.stream()
.collect(Collectors.toMap(
@ -391,18 +379,18 @@ public class EmisTmsSiteBatchMissServiceImpl extends EmisBaseService implements
// 批量插入 - 每次插入5000条
if (!uniqueBatchStatus.isEmpty()) {
int batchSize = 5000;
for (int i = 0; i < uniqueBatchStatus.size(); i += batchSize) {
int end = Math.min(i + batchSize, uniqueBatchStatus.size());
int insertBatchSize = 5000;
for (int i = 0; i < uniqueBatchStatus.size(); i += insertBatchSize) {
int end = Math.min(i + insertBatchSize, uniqueBatchStatus.size());
List<EmisWaybillBatchStatus> batch = uniqueBatchStatus.subList(i, end);
emisWaybillBatchStatusMapper.batchInsertEmisWaybillBatchStatus(batch);
totalBatchStatusRecords += batch.size();
}
}
if (!uniqueMissRecords.isEmpty()) {
int batchSize = 5000;
for (int i = 0; i < uniqueMissRecords.size(); i += batchSize) {
int end = Math.min(i + batchSize, uniqueMissRecords.size());
int insertBatchSize = 5000;
for (int i = 0; i < uniqueMissRecords.size(); i += insertBatchSize) {
int end = Math.min(i + insertBatchSize, uniqueMissRecords.size());
List<EmisTmsSiteBatchMiss> batch = uniqueMissRecords.subList(i, end);
emisTmsSiteBatchMissMapper.batchInsertEmisTmsSiteBatchMiss(batch);
totalMissRecords += batch.size();
@ -425,6 +413,21 @@ public class EmisTmsSiteBatchMissServiceImpl extends EmisBaseService implements
}
} catch (Exception e) {
log.error("Error in autoScanSiteBatch", e);
} finally {
// 确保线程池资源释放
if (executorService != null && !executorService.isShutdown()) {
executorService.shutdown();
try {
if (!executorService.awaitTermination(30, TimeUnit.SECONDS)) {
log.warn("Thread pool did not terminate gracefully, forcing shutdown");
executorService.shutdownNow();
}
} catch (InterruptedException e) {
log.error("Thread pool shutdown interrupted", e);
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
}