java 多线程批量更新10万级的数据

这篇具有很好参考价值的文章主要介绍了java 多线程批量更新10万级的数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

       好久没有写文章,今天刚好没啥事,就动手记录一下,好记性不如烂笔头!言归正传,我最近接到的一个工作任务大概内容是,有一张数据量在十万+级别的表,需要新增一个字段,并且要写入初始化值。

       业务其实非常的简单,全部查询出来一个列表,然后用mybatis的updateBatch批量更新,其实在我的实践过程中也没什么问题,但是执行的效率是很低的,而且一旦数据量过大,如果机器配置不太行的话,很可能会直接OOM,如果在正式环境出现这个问题,那完犊子,准备删库跑路!

       所以呢,我就想了一个比较保险但是比较低级的办法,每次查询出5000条数据,去做批量更新,确保内存不会溢出导致服务崩盘,这当然也是可以解决问题,但是就是修复数据需要执行很多次,显得比较愚蠢一点。

       那么如何用比较方便,并且高效的方式来修复大数量的数据呢? 第一反应肯定是多线程啦,方案是:

1.查询出全部的数据(10万条)

2.对数据进行分批,每批5000条,

3.多线程同时处理多批数据

4.等待执行完成,返回成功

直接上核心代码吧,写一个通用的分批工具类,把一个List集合,拆分成多个小的List集合

/**
 * 拆分集合
 *
 * @param <T> 泛型对象
 * @param resList 需要拆分的集合
 * @param subListLength 每个子集合的元素个数
 * @return 返回拆分后的各个集合组成的列表
 **/
public static <T> List<List<T>> splitList(List<T> resList, int subListLength) {
    if (CollectionUtils.isEmpty(resList) || subListLength <= 0) {
        return new ArrayList<>();
    }
    List<List<T>> ret = new ArrayList<>();
    int size = resList.size();
    if (size <= subListLength) {
        // 数据量不足 subListLength 指定的大小
        ret.add(resList);
    } else {
        int pre = size / subListLength;
        int last = size % subListLength;
        // 前面pre个集合,每个大小都是 subListLength 个元素
        for (int i = 0; i < pre; i++) {
            List<T> itemList = new ArrayList<>(subListLength);
            for (int j = 0; j < subListLength; j++) {
                itemList.add(resList.get(i * subListLength + j));
            }
            ret.add(itemList);
        }

        // last的进行处理
        if (last > 0) {
            List<T> itemList = new ArrayList<>(last);
            for (int i = 0; i < last; i++) {
                itemList.add(resList.get(pre * subListLength + i));
            }
            ret.add(itemList);
        }
    }
    return ret;
}
然后就是用多线程业务处理了,代码如下
 public static void doThreadBusiness(List<String> totalList) {
        Long startTime = System.currentTimeMillis();
        System.out.println("本次更新任务开始");
        System.out.println("本机CPU核心数:"+Runtime.getRuntime().availableProcessors());
        List<String> updateList = new ArrayList();
        // 初始化线程池, 参数一定要一定要一定要调好!!!!
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 50,
                4, TimeUnit.SECONDS, new ArrayBlockingQueue(10), new ThreadPoolExecutor.DiscardPolicy());
        // 大集合拆分成N个小集合,然后用多线程去处理数据,确保不会因为数据量过大导致执行过慢
        List<List<String>> splitNList = SplitListUtils.splitList(totalList, 5000);
        // 记录单个任务的执行次数
        CountDownLatch countDownLatch = new CountDownLatch(splitNList.size());
        // 对拆分的集合进行批量处理, 先拆分的集合, 再多线程执行
        for (List<String> singleList : splitNList) {
            // 线程池执行
            threadPool.execute(new Thread(new Runnable(){
                @Override
                public void run() {
                    //模拟执行时间
                    System.out.println("当前线程:"+Thread.currentThread().getName());
                    List<String> batchUpdateVipList = new ArrayList<>();
                    for (String str : singleList) {
                        //组装要执行的批量更新数据
                        batchUpdateVipList.add(str);
                    }
                    // 这里模拟执行数据库批量更新操作
                    System.out.println("本次批量更新数据量:"+ batchUpdateVipList.size());
                    // 任务个数 - 1, 直至为0时唤醒await()
                    countDownLatch.countDown();
                }
            }));
        }
        try {
            // 让当前线程处于阻塞状态,直到锁存器计数为零
            countDownLatch.await();
        } catch (Exception e) {
            System.out.println("系统出现异常");
        }
        Long endTime = System.currentTimeMillis();
        Long useTime = endTime - startTime;
        System.out.println("本次更新任务结束,共计用时"+useTime+"毫秒");
    }

代码很 简单一看就懂了,这里要说一下CountDownLatch的使用,其实开发中并不常用,但是面试却很常用,这里蛮写一下,我使用CountDownLatch来阻塞主线程,等待多线程执行完毕后,再继续主线程,返回更新的结果,这个场景其实很经常使用到。 如果不用CountDownLatch,主线程会马上返回,如果是数据量大的情况下,往往会执行蛮久的,但是结果秒返回,就会给人一种错觉。

CountDownLatch countDownLatch = new CountDownLatch(splitNList.size());

 在线程执行完毕后,需要调用一下countDown,

// 任务个数 - 1, 直至为0时唤醒await()
countDownLatch.countDown();

在主线程用await()进行阻塞等待,这样主线程就会一直等到所有的子线程都执行完成了,继续执行主线程的后续代码

 countDownLatch.await();

 其实这里面还有一个非常重要的面试点,就是多线程的七大参数如何设置,

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 
50,
4, 
TimeUnit.SECONDS, 
new ArrayBlockingQueue(10), 
new ThreadPoolExecutor.DiscardPolicy()
);

有兴趣了解具体是设置方法可以另行查询资料,这也是面试必问的考点。最后贴一下返回的打印结果吧,如下图所示:

一次性执行10万次update,技术篇,java,开发语言文章来源地址https://www.toymoban.com/news/detail-852415.html

到了这里,关于java 多线程批量更新10万级的数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 前端如何处理后端一次性传来的10w条数据?

    如果你在面试中被问到这个问题,你可以用下面的内容回答这个问题,如果你在工作中遇到这个问题,你应该先揍那个写 API 的人。 为了方便后续测试,我们可以使用node创建一个简单的服务器。 然后我们的前端由一个 HTML 文件和一个 JS 文件组成。 Index.html: Index.js: 好的,这

    2024年02月02日
    浏览(38)
  • java中多线程去跑海量数据使用线程池批量ThreadPoolExecutor处理的方式和使用Fork/Join框架的方式那种效率高?

    在Java中,使用线程池(ThreadPoolExecutor)和使用Fork/Join框架来处理海量数据的效率取决于具体的应用场景和需求。下面是一些需要考虑的因素: 任务类型:如果任务是CPU密集型的,那么使用Fork/Join框架可能更高效,因为它可以自动进行任务分割和并行处理。如果任务是I/O密集

    2024年02月10日
    浏览(9)
  • MySQL 百万级/千万级表 全量更新

    业务需求:今天从生成测试环境迁移了一批百万级/千万级表的数据,领导要求将这批数据进行脱敏处理(将真实姓名 、电话、邮箱、身份证号等敏感信息进行替换)。迁移数据记录数如下(小于百万级的全量更新不是本文重点): 表名 表名含义 行记录数 base_house 房屋表 42

    2024年02月05日
    浏览(12)
  • 【工具分享】批量多目录图片如何转换PDF,一次性转换多级目录批量的PDF的转换,合并,输出另存等问题

    【工具分享】批量多目录图片如何转换PDF,一次性转换多级目录批量的PDF的转换,合并,输出另存等问题

     在工作中我们经常要对图片进行批量转换PDF,由于文件量比较多,目录比较深,工作量比较大比较耗时费力,今天我们分享的主要解决以下问题: 1、单张图片的转换PDF:一张图临时转一下 2、多张图片转换成PDF:多张图单独转成PDF 3、多级目录多张图转换成PDF:多级目录多

    2024年02月10日
    浏览(33)
  • Java8 实现批量插入和更新,SpringBoot实现批量插入和更新,Mybatis实现批量插入和更新

    基于mybatis实现的批量插入和更新 由于直接执行批量所有数据可能会出现长度超出报错问题,使用如下方式即可解决 原理还是分配执行,这里的100就是设定每次执行最大数 这里使用插入作为例子,也可以使用批量更新 更新的写法

    2024年02月12日
    浏览(16)
  • 使用Python将图像转换为PDF:一次性解决您的批量转换需求

    使用Python将图像转换为PDF:一次性解决您的批量转换需求

    导语: 在数字化时代,我们经常需要处理大量的图像文件。将这些图像转换为PDF格式可以方便地存档、分享和打印。本文将介绍如何使用Python编程语言将图像批量转换为PDF,并提供了一个简单易用的图形界面来跟踪转换进度。 在开始之前,请确保您已经安装了以下库: PyM

    2024年02月14日
    浏览(40)
  • Java中处理千万级数据的最佳实践:性能优化指南

    在今天的数字化时代,处理大规模数据已经成为许多Java应用程序的核心任务。无论您是构建数据分析工具、实现实时监控系统,还是处理大规模日志文件,性能优化都是确保应用程序能够高效运行的关键因素。本指南将介绍一系列最佳实践,帮助您在处理千万级数据时提高

    2024年02月03日
    浏览(17)
  • MFC一次性开多个线程的简单示例

    MFC一次性开多个线程的简单示例

    为了使用mfc,先包含afxwin.h; afxwin.h是MFC C++类库的必需文件,其中包含如CWin,CStatic,CButton,CString,CEdit等类运行所必需的头文件;它还会调用windows.h,该头文件包含有数据类型的定义、API入口点定义和其它有用的参数信息; Afx前缀是微软MFC一个小组的名称简写,并没有别的

    2024年01月25日
    浏览(34)
  • java使用jdbcTemplate查询并插入百万级数据解决方案

    java使用jdbcTemplate查询并插入百万级数据解决方案

    背景:使用JdbcTemplate查询500万数据,然后插入到数据库。 这么多的数据按照普通的方式直接查询然后插入,服务器肯定会挂掉,我尝试过使用分页查询的方式去进行分批查询插入,虽然也能达到保证服务器不挂掉的效果,但是有一个严重的问题,每次查询的数据很难保证顺序

    2024年02月03日
    浏览(8)
  • 如何一次性更新python所有的库?

    我们可以使用  pip  命令来更新 Python 库。 在命令提示符或终端中,使用pip install --upgrade后面跟上要更新的库的名称。 例如,如果你想更新名为  numpy  的库,你可以在 Windows 上打开命令提示符,在 macOS 或 Linux 上打开终端,然后输入以下命令: 这将升级  numpy  库到最新版

    2024年02月09日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包