1.场景。 大概有3000来条数据,需要做校验,过滤,最后插入数据库
2.大致代码与大致思路
接收所需数据,并将3000条数据分组成每组上限100条的集合,将每个集合分别放在我们创建的线程中,并将线程池的最大工作线程数量设置为10。
这里比较重要的就是 CountDownLatch 允许一个或者多个线程去等待其他线程完成操作,它里面有个计数器,如果减到了0,则会唤醒所有等待在这个latch上的线程。
latch.await() 使当前线程进入同步队列进行等待,直到latch的值被减到0或者当前线程被中断,当前线程就会被唤醒 。 我们这里是在 使用线程池处理数据后加的 ,因为 线程默认是异步的 ,可能会出现 主线程结束而 子线程没有结束的情况,所以必须等待线程全部走完 ,这样才知道插入是否是真的成功
public void onlineConfirmImport(MultipartFile file, Integer agencyAgreementType) {
String errorImport = "导入模板不正确";
// 获取上传数据
List<OnlineConfirmExportVO> loadExcelData = loadExcelData(file);
//校验数据格式是不是都是正确的
for (OnlineConfirmExportVO onlineConfirm1 : loadExcelData) {
//省略
}
//将集合分为100条一组
List<List<OnlineConfirmExportVO>> list = Lists.partition(loadExcelData, MagicNumConstant.ONE_HUNDRED);
//CountDownLatch允许一个或者多个线程去等待其他线程完成操作,相当于等待队列
CountDownLatch latch = new CountDownLatch(list.size());
int threadPoolMax = Math.min(list.size(), MagicNumConstant.TEN);
//设置线程池
ThreadFactory springThreadFactory = new CustomizableThreadFactory("registrationThread-pool-");
ExecutorService threadPool = Executors.newFixedThreadPool(threadPoolMax, springThreadFactory);
//利用多线程去添加数据
for (int i = 0; i < list.size(); i++) {
List<OnlineConfirmExportVO> subList = list.get(i);
ImportData importData = new ImportData(subList,latch,i,agencyAgreementType);
threadPool.execute(importData);
}
try {
latch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
//最后关闭线程池
threadPool.shutdown();
}
}
设置多线程
在做完了对应的业务逻辑操作后,使用 latch.countDown() 减少锁存器的计数
class ImportData implements Runnable {
private List<OnlineConfirmExportVO> list;
private CountDownLatch latch;
private Integer i;
private Integer agencyAgreementType;
public ImportData(List<OnlineConfirmExportVO> list, CountDownLatch latch, Integer i, Integer agencyAgreementType) {
this.list = list;
this.latch = latch;
this.i = i;
this.agencyAgreementType = agencyAgreementType;
}
@Override
public void run() {
log.info("线程" + i + "开始执行,数据条数:" + list.size());
String errorImport = "导入模板不正确";
try {
log.info("线程" + i + "执行结束,数据条数:" + list.size());
} catch (Exception e) {
log.error("Catch OnlineConfirm import Exception:", e);
} finally {
//减少锁存器的计数,如果计数达到零,则释放所有等待线程
latch.countDown();
}
}
}
补充:
这里的线程池还可以这样用
poolExecutor.execute(() -> {
simpleExecute(scriptId, executingMachineId, threadNumber, rampUpPeriod, duration);
});
把CountDownLatch 当作参数传过去就可以了