利用多线程将大数据插入数据库

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 当作参数传过去就可以了

猜你喜欢

转载自blog.csdn.net/weixin_45933454/article/details/126142894