并发查询数据库并做汇总处理(多线程+CompletableFuture方式)

文章目录

  • 1.需求说明
  • 2.准备工作
  • 3.线程池执行
  • 4.使用CompletableFuture

1.需求说明

我们想要通过更快的方式查询10w条user表数据内容,做数据的汇总,得到10w个用户的年龄分布。

此时很容易想到用多线程处理,但知易行难,还是动手来写写吧。

2.准备工作

我贴心的为大家准备了数据库脚本,直接执行即可。

-- 创建user表  
CREATE TABLE user (  id INT AUTO_INCREMENT PRIMARY KEY,  name VARCHAR(50) NOT NULL,  age INT NOT NULL  
);  -- 插入10万条数据  
DELIMITER //  
CREATE PROCEDURE InsertData()  
BEGIN  DECLARE i INT DEFAULT 0;  WHILE i < 100000 DO  INSERT INTO user (name, age) VALUES (CONCAT('Name', i), FLOOR(RAND() * 100));  SET i = i + 1;  END WHILE;  
END //  
DELIMITER ;  -- 调用存储过程插入数据  
CALL InsertData();

User类

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@TableName("user")
public class User {@TableId(value = "id", type = IdType.AUTO)private Integer id;@TableField("name")private String name;@TableField("age")private Integer age;}

分页插件,这个很重要,不然分页失效,数据就会有问题了。

@Configuration
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}} 

自定义线程池配置,这里有个小技巧,因为我们是针对数据库查询,是IO操作,所以更应该创建更多的线程,避免cpu的空闲,当然,实际证明对于这个查询来讲保持和cpu核心数相同即可,多一点差距也不大。

@Configuration
public class ThreadPoolConfig {@Bean("defaultExecutor")public ThreadPoolTaskExecutor orderLogExecutor() {ThreadPoolTaskExecutor orderLogExecutor = new ThreadPoolTaskExecutor();//设置线程池参数信息orderLogExecutor.setCorePoolSize(20);orderLogExecutor.setMaxPoolSize(50);orderLogExecutor.setQueueCapacity(100);orderLogExecutor.setKeepAliveSeconds(60);orderLogExecutor.setThreadNamePrefix("Default-userOper-Executor-");orderLogExecutor.setWaitForTasksToCompleteOnShutdown(true);orderLogExecutor.setAwaitTerminationSeconds(60);//修改拒绝策略为使用当前线程执行orderLogExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//初始化线程池orderLogExecutor.initialize();return orderLogExecutor;}}

3.线程池执行

首先我们就要想到应该用多线程分页拿到部分数据,进行处理,最终做个汇总。

具体代码如下,我来进行下说明。

@Slf4j
@Service
public class UserService extends ServiceImpl<UserMapper,User> {@Autowiredprivate Executor defaultExecutor;//目的: 分页查询10000条数据  进行数据处理 调用多个线程分别查询 处理  最后汇总 统计用户的年龄分段public void pageSum() {int max = 100000;int split = 20;int size = max / split;AtomicInteger atomicInteger = new AtomicInteger(0);CountDownLatch countDownLatch = new CountDownLatch(split);Map<Integer, Integer>  map= new ConcurrentHashMap<>();for (int i = 1; i <= split; i++) {int finalI = i;defaultExecutor.execute(() -> {log.info("当前线程:{}", Thread.currentThread().getName());Page<User> page = this.page(new Page<>(finalI, size));List<User> records = page.getRecords();atomicInteger.addAndGet(records.size());for (User record : records) {Integer age = record.getAge();map.compute(age, (key, value) -> value == null ? 1 : value + 1);}log.info("当前线程完成查询:{}", Thread.currentThread().getName());countDownLatch.countDown();});}try {countDownLatch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}log.info("最终汇总的数据:{}", map);log.info("最终汇总的数据大小:{}", atomicInteger.get());}
}

1.我们通过max,split来进行分割,在for循环中进行数据的查询,保证了每次得到的数据是不同的,如果出现了数据重叠说明分页出现了问题。

2.使用CountDownLatch 来保证所有线程执行完毕后再进行汇总,当然,这里最好有没有进行汇总,但好处在于,方法不会直接执行完毕,而是会进行等待。

3.使用,ConcurrentHashMapmap.compute等,防止了数据的竞争,该方法是线程安全的。

最终执行效果如下,10w条查询用时8s多,还是可以的,比单线程快多了。

在这里插入图片描述

4.使用CompletableFuture

使用CompletableFuture,不要忘记内部装入线程池,否则用的是系统默认的,还不如不用呢。

 public void  pageUseCompatableFuture() {// 创建并启动多个 CompletableFuture 任务来并发查询数据库int max = 100000;int split = 20;int size = max / split;AtomicInteger atomicInteger = new AtomicInteger(0);Map<Integer, Integer> map = new ConcurrentHashMap<>();List<CompletableFuture> futures = new ArrayList<>();for (int i = 1; i <= split; i++) {int finalI = i;CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {log.info("当前线程:{}", Thread.currentThread().getName());Page<User> userPage = this.page(new Page<>(finalI, size));List<User> records = userPage.getRecords();atomicInteger.addAndGet(records.size());for (User record : records) {Integer age = record.getAge();// 细节 线程安全的合并方法 如果单单使用put会有线程安全问题map.compute(age, (key, value) -> value == null ? 1 : value + 1);}log.info("当前线程完成查询:{}", Thread.currentThread().getName());return null;}, defaultExecutor);// 装入集合方便后续处理futures.add(future);}// 所有结果使用allof处理 如果还需操作则往后接whenxx即可CompletableFuture<Void> allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));// 这里只需要等待其他操作完成即可 不做处理allOf.join();log.info("最终汇总的数据:{}", map);log.info("最终汇总的数据大小:{}", atomicInteger.get());}

1.supplyAsync方法可以保证异步执行,里面传入一个提供者函数式接口,这里因为无需返回什么东西,所以用了Void作为返回值。
2.将所有的future装入了集合中,最终通过allOf 进行处理,后面没有汇总操作,但是也可以自定义加上,而后面的allOf.join()起到了和上面countDownLatch类似的效果,但看起来更加的直观。

最终的结果也和上面相同,用时也差不多,但个人认为后一种方式更加酷炫哈哈。
在这里插入图片描述

总结下,
1.多线程编程的难点在于数据竞争导致的数据错乱问题,不懂的api一定要查资料验证后再使用,不要盲目使用。

2.还有就是,脑子以为会了?不如代码写一下,相信还是会遇到问题的,不要想当然。

其实我们都是普通人 想着比别人花更少的时间做更多的事 其实是奢望 普通人只有专注一道 获得很精深的经验才能突破

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2661988.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

rsync的介绍与使用

rsync的介绍与使用 一、简介 rsync&#xff08;remote synchronize&#xff09;是Liunx/Unix下的一个远程数据同步工具。它能够以非常高效的方式传输和同步文件&#xff0c;它可以将一个目录的文件快速地同步到另一个目录&#xff0c;还可以通过网络快速同步多台主机间的文件…

【VTK-Rendering::Core】第一期 vtkCoordinate坐标系统

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ&#xff1a;870202403 前言 本文分享vtkCoordinate源码解析&#xff0c;并对VTK中的各种坐标变换进行分析&#xff0c;希望对各位小伙伴有所帮助&#xff01; 感谢各位小伙伴的点赞关注&#xff0c;小易会继续努力分享&#xff…

AIGC时代下,结合ChatGPT谈谈儿童教育

引言 都2024年了&#xff0c;谈到儿童教育&#xff0c;各位有什么新奇的想法嘛 我觉得第一要务&#xff0c;要注重习惯养成&#xff0c;我觉得聊习惯养成这件事情范围有点太大了&#xff0c;我想把习惯归纳于底层逻辑&#xff0c;我们大家都知道&#xff0c;在中国式教育下&a…

Glary Utilities Pro - 电脑系统优化全面指南:详尽使用教程

软件简介&#xff1a; Glary Utilities Pro 是一款全面的电脑优化工具&#xff0c;它旨在帮助用户提升计算机的性能和稳定性。这款软件提供了多种功能&#xff0c;包括系统清理、优化、修复以及保护。通过一键扫描&#xff0c;它可以识别并清除无用文件、临时数据、注册表错误等…

AIGC开发:调用openai的API接口

简介 开始进行最简单的使用&#xff1a;通过API调用openai的模型能力 OpenAI的能力如下图&#xff1a; 文本生成模型 OpenAI 的文本生成模型&#xff08;通常称为生成式预训练 Transformer 或大型语言模型&#xff09;经过训练可以理解自然语言、代码和图像。这些模型提供文…

这是蛰伏的第 1 年 —— 2023 年度总结

时间过得老快了&#xff0c;一下子就到 2023 年年底了&#xff0c;感觉自己好像什么都没做似的。 不过&#xff0c;又到了年终总结季了&#xff0c;正好跟大家唠唠嗑&#xff0c;我就想到啥说啥了。 工作淡如水 先聊聊工作的事情。回顾过去一年的工作&#xff0c;我最大的感…

微软CEO纳德拉当选2023年度CEO,AI大模型崛起成重要趋势;Mixtral 8x7B 真的击败了 GPT 3.5 Turbo 吗?

&#x1f989; AI新闻 &#x1f680; 微软CEO纳德拉当选2023年度CEO&#xff0c;AI大模型崛起成重要趋势 摘要&#xff1a;2023年被认为是AI大模型崛起之年&#xff0c;微软CEO纳德拉凭借对AI的投资和领导力当选2023年度CEO。纳德拉将AI技术融入微软的产品和服务中&#xff0…

【解决问题】pyinstaller打包python应用进行快速分发

pyinstaller打包python应用进行快速分发 问题起因先利其器再善其事试用运行 问题起因 有同学问我要接口的应用&#xff0c;于是试了一下python打包成exe的过程。 先利其器 主要使用pyinstaller&#xff0c;可以通过pip安装 pip install pyinstaller安装过程如图 再善其事…

微服务全链路灰度方案介绍

目录 一、单体架构下的服务发布 1.1 蓝绿发布 二、微服务架构下的服务发布 三、微服务场景下服务发布的问题 四、全链路灰度解决方案 4.1 物理环境隔离 4.2 逻辑环境隔离 4.3 全链路灰度方案实现技术 4.3.1 标签路由 4.3.2 节点打标 4.3.3 流量染色 4.3.4 分布式链路…

力扣题目学习笔记(OC + Swift)19. 删除链表的倒数第 N 个结点

19. 删除链表的倒数第 N 个结点 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 此题目为链表题&#xff0c;拿出我们的杀手锏&#xff0c;链表解题经典三把斧&#xff1a; 哑巴节点栈快慢指针 关于内存问题&#xff1a;由于Swift及…

无论男孩女孩都要尽情打扮

这款柔软又细腻的开衫外套 上身体验感很不错的哈 舒适软糯百搭还透气&#xff0c;抗起球的面料 黑灰两色简单大方 胸前加上了流行的刺绣设计&#xff0c;可爱又精致 单穿内搭都可&#xff0c;现在天气还比较冷 外面可以套个羽绒服之类的 时尚叠穿风&#xff0c;韩系范儿…

Web自动化测试:Selenium入门到精通

前言 说到自动化测试&#xff0c;就不得不提大名鼎鼎的Selenium。Selenium 是如今最常用的自动化测试工具之一&#xff0c;支持快速开发自动化测试框架&#xff0c;且支持在多种浏览器上执行测试。 Selenium学习难度小&#xff0c;开发周期短。对测试人员来说&#xff0c;如果…

模版匹配历劫之路1-匹配点太多如何解决

1测试图片 2初步推测是否是提取的点太多而导致匹配时间很长 2.1通过canny的算法来提取检测点 import numpy as np import cv2 import time import matplotlib.pyplot as pltclass GeoMatch:def __init__(self):self.noOfCordinates0 # 坐标数组中元素的个数self.cordinates…

ArcGIS批量计算shp面积并导出shp数据总面积(建模法)

在处理shp数据时&#xff0c; 又是我们需要知道许多个shp字段的批量计算&#xff0c;例如计算shp的总面积、面积平均值等&#xff0c;但是单个查看shp文件的属性进行汇总过于繁琐&#xff0c;因此可以借助建模批处理来计算。 首先准备数据&#xff1a;一个含有多个shp的文件夹。…

C++ Qt开发:SqlRelationalTable关联表组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍SqlRelationalTable关联表组件的常用方法及灵…

想畅游在全球顶级金融学识的海洋——人民大学与加拿大女王大学金融硕士

金融职场的你是否想象过有朝一日能够畅游在全球顶级金融学识的海洋中呢&#xff1f;在那里&#xff0c;你可以尽情探索和领略全球顶尖的金融学识的魅力与深度&#xff0c;与来自世界各地的专业人士共同交流和分享经验。这样的场景让人感到兴奋和向往&#xff0c;准备好了吗&…

Goal-Auxiliary Actor-Critic for 6D Robotic Grasping with Point Clouds

题目&#xff1a;基于点云的 6D 机器人抓取目标-辅助行为-评价 摘要&#xff1a;6D 机 器 人 抓 取超 越 自上 而 下捡 垃 圾桶 场 景是 一 项具 有 挑战 性 的任 务 。 以往基于 6 D 抓 取综 合和 机器 人运 动 规划 的解 决方 案 通常 在开 环设 置下 运 行&#xff0c; 对抓…

轻松实现电脑对iPhone应用管理

目录 摘要 引言 用户登录工具和连接设备 电脑可对手机应用程序批量操作 运行APP和查看APP日志 IPA包安装测试 摘要 本文介绍了如何使用克魔助手工具实现电脑对手机应用的管理操作。通过简单的步骤&#xff0c;用户可以批量操作手机应用、运行应用、查看应用日志以及安装测…

企业如何做好内容?媒介盒子分享

在个性化算法的支持下&#xff0c;企业通过创作优质内容使消费者主动选择企业的时代已经来临&#xff0c;对于中小企业来说&#xff0c;这是能够低成本进行营销的好机会。但是有许多企业对内容的理解依旧是片面的&#xff0c;今天媒介盒子就来和大家聊聊&#xff1a;企业如何做…

autosar SJBWY 开发

第一天&#xff1a; 解决tasking 增加任意目录源文件的问题&#xff1b; 展开 Advanced 下面 Browse...选你的源文件目录就好了&#xff1b;