当前位置: 首页 > 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线程的。

相关文章:

  • Spring日志引用原理
  • 项目实战 | 基于RK3566开发板实现USB摄像头推流(ffmpeg+nginx)
  • 进程的程序替换
  • 9. SQL中Insert into/Update/Delete的用法
  • 【webGoat】Path traversal
  • 前后端分离的项目——图书管理系统
  • 【C++修炼秘籍】类和对象(一)
  • 【已解决】利用 Java 多线程并发编程处理数据的实践记录
  • Roson的Qt之旅 #125 QNetworkCookie(网络Cookie)
  • SpringMVC入门案例的步骤
  • 【云原生 | 33】Docker快速部署主流编程语言C/C++
  • 集合和数组之间的相互转换
  • AtCoder Beginner Contest 271 C Manga(贪心 set 注意事项)
  • 导入项目后无法识别Controller、RequestMapping注解
  • 漫水填充算法填充图案 (C++)
  • “大数据应用场景”之隔壁老王(连载四)
  • 《Java8实战》-第四章读书笔记(引入流Stream)
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • 【译】理解JavaScript:new 关键字
  • 〔开发系列〕一次关于小程序开发的深度总结
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • js如何打印object对象
  • js作用域和this的理解
  • pdf文件如何在线转换为jpg图片
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • 安卓应用性能调试和优化经验分享
  • 飞驰在Mesos的涡轮引擎上
  • 基于webpack 的 vue 多页架构
  • 来,膜拜下android roadmap,强大的执行力
  • 浅谈web中前端模板引擎的使用
  • 设计模式 开闭原则
  • 深度解析利用ES6进行Promise封装总结
  • 探索 JS 中的模块化
  • 详解NodeJs流之一
  • 详解移动APP与web APP的区别
  •  一套莫尔斯电报听写、翻译系统
  • 一些css基础学习笔记
  • 【干货分享】dos命令大全
  • 选择阿里云数据库HBase版十大理由
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • ​香农与信息论三大定律
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #大学#套接字
  • #预处理和函数的对比以及条件编译
  • (11)MATLAB PCA+SVM 人脸识别
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (分类)KNN算法- 参数调优
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (十三)Maven插件解析运行机制
  • (五)关系数据库标准语言SQL