当前位置: 首页 > news >正文

【已解决】利用 Java 多线程并发编程处理数据的实践记录

🎉工作场景中遇到这样一个需求:根据主机的 IP 地址联动更新其他模型的相关信息。需求很简单,只涉及一般的数据库联动查询以及更新操作,然而在编码实现过程中发现,由于主机的数量很多,导致循环遍历查询、更新时花费很长的时间,调用一次接口大概需要 30-40 min 时间才能完成操作。

💡因此,为了有效缩短接口方法的执行时间,便考虑使用多线程并发编程方法,利用多核处理器并行执行的能力,通过异步处理数据的方式,便可以大大缩短执行时间,提高执行效率。

📍这里使用可重用固定线程数的线程池 FixedThreadPool,并使用 CountDownLatch 并发工具类提供的并发流程控制工具作为配合使用,保证多线程并发编程过程中的正常运行:

  • 首先,通过 Runtime.getRuntime().availableProcessors() 方法获取运行机器的 CPU 线程数,用于后续设置固定线程池的线程数量。
  • 其次,判断任务的特性,如果为计算密集型任务则设置线程数为 CPU 线程数+1,如果为 IO 密集型任务则设置线程数为 2 * CPU 线程数,由于在方法中需要与数据库进行频繁的交互,因此属于 IO 密集型任务。
  • 之后,对数据进行分组切割,每个线程处理一个分组的数据,分组的组数与线程数保持一致,并且还要创建计数器对象 CountDownLatch,调用构造函数,初始化参数值为线程数个数,保证主线程等待所有子线程运行结束后,再进行后续的操作。
  • 然后,调用 executorService.execute() 方法,重写 run 方法编写业务逻辑与数据处理代码,执行完当前线程后记得将计数器减1操作。
  • 最后,当所有子线程执行完成后,关闭线程池。

✨在省略工作场景中的业务逻辑代码后,通用的处理方法示例如下所示:

public ResponseData updateHostDept() {
		//to do something
		List<Map> mapList = mongoTemplate.find(query, Map.class, "host");
        //split the mapList for the following multi-threads task
        //return the number of logical CPUs
        int processorsNum = Runtime.getRuntime().availableProcessors();
        //set the threadNum as 2*(the number of logical CPUs) for handling IO Tasks,
        //if Computing Tasks set the threadNum as (the number of logical  CPUs) + 1
        int threadNum = processorsNum * 2;  
        int eachGroupNum = mapList.size() / threadNum; //分组后每组的数据个数
        List<List<Map>> groupList = new ArrayList<>();
        for (int i = 0; i < threadNum; i++) {
            int start = i * eachGroupNum;
            if (i == threadNum - 1) {
                int end = mapList.size();
                groupList.add(mapList.subList(start, end));
            } else {
                int end = (i+1) * eachGroupNum;
                groupList.add(mapList.subList(start, end));
            }
        }
        //使用线程池创建多线程异步更新数据
        ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
        CountDownLatch countDownLatch = new CountDownLatch(threadNum);
        for (List<Map> group : groupList) {
            executorService.execute(()->{
                try {
                    for (Map map : group) {
                    	//update the data in mongodb
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch.countDown();  //计数器减一
                }
            });
        }
        try {
            countDownLatch.await();  //让主线程等待所有子线程执行完成
        } catch (Exception e) {
            e.printStackTrace();
        }
        executorService.shutdown();  //关闭线程池
        return ResponseData.success();
}

🎉那么在使用多线程异步更新的策略后,从当初调用接口所需的大概时间为 30-40 min 下降到了 8-10 min,大大提高了执行效率。

🎉最后补充一点,如果想要通过非编码的方式获取机器的 CPU 线程个数也很简单,windows 系统通过任务管理器,选择 “性能”,便可以查看 CPU 线程个数的情况,如下图所示:

在这里插入图片描述
🎉从上图可以看到,我的机器中内核是八个 CPU,但是通过超线程技术一个物理的 CPU 核心可以模拟成两个逻辑 CPU 线程,因此我的机器是支持8核16线程的。

相关文章:

  • Roson的Qt之旅 #125 QNetworkCookie(网络Cookie)
  • SpringMVC入门案例的步骤
  • 【云原生 | 33】Docker快速部署主流编程语言C/C++
  • 集合和数组之间的相互转换
  • AtCoder Beginner Contest 271 C Manga(贪心 set 注意事项)
  • 导入项目后无法识别Controller、RequestMapping注解
  • 漫水填充算法填充图案 (C++)
  • Python-入门-流程控制(八)
  • 对于指针的基本了解
  • 基于BiGRU-Attention网络的 新型冠状病毒肺炎疫情预测学习记录
  • 生成对抗网络
  • C++【算法】【动态规划问题】
  • Flink中Table Api和SQL(二)
  • hook函数之useEffect的使用——自定义hook函数网络请求——
  • Windows 窗体显示的“模式方式”与“非模式方式”
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • 08.Android之View事件问题
  • 30秒的PHP代码片段(1)数组 - Array
  • bearychat的java client
  • Bytom交易说明(账户管理模式)
  • Elasticsearch 参考指南(升级前重新索引)
  • Java 多线程编程之:notify 和 wait 用法
  • Javascript Math对象和Date对象常用方法详解
  • JS数组方法汇总
  • mysql_config not found
  • React as a UI Runtime(五、列表)
  • Vue全家桶实现一个Web App
  • 让你的分享飞起来——极光推出社会化分享组件
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 网页视频流m3u8/ts视频下载
  • 怎样选择前端框架
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • # 飞书APP集成平台-数字化落地
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • (175)FPGA门控时钟技术
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (Matlab)使用竞争神经网络实现数据聚类
  • (windows2012共享文件夹和防火墙设置
  • (独孤九剑)--文件系统
  • (附源码)计算机毕业设计大学生兼职系统
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (十)T检验-第一部分
  • (十三)Maven插件解析运行机制
  • (五)MySQL的备份及恢复
  • (一)Dubbo快速入门、介绍、使用
  • (转)scrum常见工具列表
  • (状压dp)uva 10817 Headmaster's Headache
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .net core 源码_ASP.NET Core之Identity源码学习