多线程优化导入支持事务二

多线程优化导入支持事务二

可以在项目中使用的多线程导入,支持事务,异常立即回滚
使用到线程池+CountDownLatch+transactionManager+AtomicBoolean

创建线程池

java 复制代码
@Bean("taskExecutor")
    public Executor taskExecutro(){
        int i = Runtime.getRuntime().availableProcessors();
        System.out.println("系统最大线程数  : "+i);
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(i);
        taskExecutor.setMaxPoolSize(i);
        taskExecutor.setQueueCapacity(99999);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("taskExecutor--");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(60);
        return taskExecutor;
    }

切分数据,启动线程

java 复制代码
public void importExcel2() {
        List<User> list = getUserList();
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        AtomicBoolean isCommit = new AtomicBoolean(true);
        //每个线程处理200条数据
        int sliceLength = 200;
        //线程数
        int threadCount = (list.size() -1)/sliceLength + 1;

        //通过子线程进入主线程
        CountDownLatch threadToMainCdl = new CountDownLatch(threadCount);
        //通过主线程进入子线程
        CountDownLatch mainToThreadCdl = new CountDownLatch(1);
        //线程开始角标
        int startIndex = 0;
        //线程结束角标
        int endIndex = 0;
        for (int i = 0; i < threadCount; i++) {
            startIndex = i * sliceLength;
            //处理最后一条线程
            if(i == threadCount - 1){
                endIndex = list.size();
            }else{
                endIndex = (i + 1) * sliceLength;
            }
            List<User> users = list.subList(startIndex, endIndex);
            taskExecutor.execute(() -> {
                insertUser(users, isCommit,threadToMainCdl,mainToThreadCdl);
            });
        }
        try {
            boolean await = threadToMainCdl.await(30, TimeUnit.SECONDS);
            if (!await){
                isCommit.set(false);
            }
        } catch (InterruptedException e) {
            isCommit.set(false);
        }
        mainToThreadCdl.countDown();
        stopWatch.stop();
        System.out.println("导入耗时: "+stopWatch.getTotalTimeSeconds());
    }

插入数据

java 复制代码
private void insertUser(List<User> users, AtomicBoolean isCommit, CountDownLatch threadToMainCdl, CountDownLatch mainToThreadCdl) {
        TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
        Random random = new Random();
        long l = random.nextLong(10000);
        try {
            for (User user : users) {
                System.out.println("插入数据:" + user.toString());
                if(isCommit.get()){
                    userMapper.insert(user);
                TimeUnit.MILLISECONDS.sleep(100);
//            if(l > 9000){
//                int s = 10 / 0;
//            }
                }else{
                    break;
                }
            }
        } catch (Exception e) {
            isCommit.set(false);
        }finally {
            threadToMainCdl.countDown();
        }
        try {
            mainToThreadCdl.await();
        } catch (InterruptedException e) {
            isCommit.set(false);
        }
        if(isCommit.get()){
            transactionManager.commit(transaction);
        }else{
            transactionManager.rollback(transaction);
        }

    }

注意点

需要注意,线程池最大线程数要大于等于切片数,如果小于分片数会导致线程等待

相关推荐
努力努力再努力wz1 分钟前
【c++进阶系列】:万字详解AVL树(附源码实现)
java·运维·开发语言·c++·redis
爱学习de测试小白2 分钟前
13-Java-面向对象-封装和this关键字
java
-哈喽沃德-2 分钟前
Date、BigDecimal类型值转换
java
凉、介4 分钟前
U-Boot 多 CPU 执行状态引导
java·服务器·前端
一个尚在学习的计算机小白4 分钟前
spring
android·java·spring
csdn_clwjc6 分钟前
synchronized 锁升级
java·juc
脚大江山稳7 分钟前
docker使用nginxWebUI配置
java·docker·容器
Miraitowa_cheems9 分钟前
LeetCode算法日记 - Day 34: 二进制求和、字符串相乘
java·算法·leetcode·链表·职场和发展
CHANG_THE_WORLD27 分钟前
C++并发编程指南 std::promise 介绍与使用
java·开发语言·c++·promise
Bonnie_121528 分钟前
01-线上问题处理-树形结构拼接
java