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

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

可以在项目中使用的多线程导入,支持事务,异常立即回滚
使用到线程池+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);
        }

    }

注意点

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

相关推荐
Yeats_Liao14 分钟前
Spring 框架:配置缓存管理器、注解参数与过期时间
java·spring·缓存
Yeats_Liao14 分钟前
Spring 定时任务:@Scheduled 注解四大参数解析
android·java·spring
码明14 分钟前
SpringBoot整合ssm——图书管理系统
java·spring boot·spring
某风吾起18 分钟前
Linux 消息队列的使用方法
java·linux·运维
xiao-xiang21 分钟前
jenkins-k8s pod方式动态生成slave节点
java·kubernetes·jenkins
取址执行33 分钟前
Redis发布订阅
java·redis·bootstrap
S-X-S1 小时前
集成Sleuth实现链路追踪
java·开发语言·链路追踪
快乐就好ya1 小时前
xxl-job分布式定时任务
java·分布式·spring cloud·springboot
沉默的煎蛋1 小时前
MyBatis 注解开发详解
java·数据库·mysql·算法·mybatis
Aqua Cheng.1 小时前
MarsCode青训营打卡Day10(2025年1月23日)|稀土掘金-147.寻找独一无二的糖葫芦串、119.游戏队友搜索
java·数据结构·算法