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

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

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

    }

注意点

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

相关推荐
YatHinLay1 分钟前
Spring Boot + Calcite 实现跨库查询
java
酷炫码神23 分钟前
MosMos 创意效果与能力边界展示
java
Wang's Blog30 分钟前
Java 接入Redis: 使用Jedis操作Redis
java·服务器·redis
事圆则缓33 分钟前
Java 8 Lambda、Stream、Optional 与 Android 边界:从回调语法到运行时兼容
android·java
shehuiyuelaiyuehao42 分钟前
算法50,分治归并,数组中的逆序对
java·算法
烽学长43 分钟前
(附源码)基于Springboot+vue的图书阅读分享系统的设计与实现
java·spring boot·后端
Ivanqhz1 小时前
数据搬运是性能关键
java·服务器·网络·人工智能·深度学习
青山木1 小时前
RocketMQ 入门到原理(三):消息存储原理
java·后端·中间件·架构·rocketmq
MayBaymax1 小时前
Spring AI Alibaba Graph 实战:客服工单智能处理
java·ai·ai编程
光依旧2 小时前
MCP实战手记系列(五):让工具返回一个能点的界面(文末附github源码链接)
java·spring ai·前端集成·mcp·mcp apps