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

基于Java多线程处理数据

基于Java多线程处理数据

  • 背景
  • 代码实现

背景

在日常工作中,有一个同步企微客户-学员关系接口的定时任务在执行中随着数据量的不断增长,定时任务的执行结束时间也出现了当天执行不完的情况,影响到了正常业务的运行。基于这种情况,在对该定时任务的业务逻辑代码分析验证后得出是调用企微客户-学员关系接口时耗时引起的,但是查阅企微接口文档,又不支持批量调用,只能逐个调用。那么这种情况下既然批量调用接口不支持,那么可以采用多线程并发调用的方式来降低定时任务整体的执行时间,于是就需要用到线程池来进行多线程操作。

代码实现

在这里我将会使用spring自带的线程池类 ThreadPoolTaskExecutor 来进行处理, ThreadPoolTaskExecutor 是对 ThreadPoolExecutor 进行了封装处理,源代码中可以看到
在这里插入图片描述
而线程池类ThreadPoolExecutor 是JDK的线程池类,继承 AbstractExecutorService ,
public class ThreadPoolExecutor extends AbstractExecutorService {
AbstractExecutorService 实现 ExecutorService,
public abstract class AbstractExecutorService implements ExecutorService {
ExecutorService 继承 Executor
public interface ExecutorService extends Executor {
下面开始初始化线程池类 ThreadPoolTaskExecutor,配置类 ThreadPoolConfig 代码如下

/*** 线程池配置***/@Configurationpublic class ThreadPoolConfig{// 核心线程池大小private int corePoolSize = 50;// 最大可创建的线程数private int maxPoolSize = 200;// 队列最大长度private int queueCapacity = 1000;// 线程池维护线程所允许的空闲时间private int keepAliveSeconds = 300;@Bean(name = "threadPoolTaskExecutor")public ThreadPoolTaskExecutor threadPoolTaskExecutor(){ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setMaxPoolSize(maxPoolSize);executor.setCorePoolSize(corePoolSize);executor.setQueueCapacity(queueCapacity);executor.setKeepAliveSeconds(keepAliveSeconds);// 线程池对拒绝任务(无线程可用)的处理策略executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());return executor;}}

补充同步企微客户-学员关系定时任务 SyncWechatWorkCustomerLinkDetailHandler 代码如下

@Component@JobHandler("syncWechatWorkCustomerLinkDetailHandler")public class SyncWechatWorkCustomerLinkDetailHandler extends IJobHandler {@Autowiredprivate IWechatCustomerLinkDetailService wechatCustomerLinkDetailService;@Overridepublic ReturnT<String> execute(String params) throws Exception {wechatCustomerLinkDetailService.syncWechatWorkCustomerLinkDetail(params);return ReturnT.SUCCESS;}}

业务处理实现类 syncWechatWorkCustomerLinkDetail 代码如下

    @Overridepublic void syncWechatWorkCustomerLinkDetail(String params) {XxlJobLogger.log("补充任务开始执行...[{}]",params);//查询条件对象WechatCustomerLinkDetail searchparam = new WechatCustomerLinkDetail();if (StringUtils.isNotEmpty(params)) {Long[] ids = Convert.toLongArray(params);//根据ids查询数据searchparam.setLinkIds(ids);}// 分页查询企微获客助手客户链接int pageNo = 0;int pageSize = 200;while(true){pageNo++;XxlJobLogger.log("第【{}】页数据开始补充...",pageNo);PageHelper.startPage(pageNo, pageSize);PageHelper.orderBy("id asc");List<WechatCustomerLinkDetail> list = wechatCustomerLinkDetailMapper.selectWechatCustomerLinkDetailList(searchparam);PageHelper.clearPage();if (CollUtil.isEmpty(list) ) {break;}//开始补充数据multiThreadProcessData(list);XxlJobLogger.log("第【{}】页数据补充完成...",pageNo);}}

多线程处理列表中的数据类 multiThreadProcessData 代码如下

    /*** 使用多线程处理列表中的数据* @param list 待处理的微信客户链接详情列表*/public void multiThreadProcessData(List<WechatCustomerLinkDetail> list) {// 将大集合分割为多个小集合,以便多线程处理List<List<WechatCustomerLinkDetail>> partitionData = partitionData(list, 10);// 获取线程池执行器ThreadPoolTaskExecutor executor = SpringUtils.getBean("threadPoolTaskExecutor");// 创建计数器,用于线程同步CountDownLatch latch = new CountDownLatch(partitionData.size());for (List<WechatCustomerLinkDetail> details : partitionData) {// 提交任务给线程池执行,每个任务负责处理一个分割后的列表executor.execute(() -> {try {for (WechatCustomerLinkDetail detail : details) {//打印线程名称//System.out.println("name========"+Thread.currentThread().getName());// 对每个详情进行处理,填充微信用户名称信息  这里就是业务逻辑处理的地方fillWechatUserNameInfo(detail);}} catch (Exception e) {// 捕获异常并打印,避免线程异常中断e.printStackTrace();} finally {// 处理完成后,计数器减一,用于线程同步latch.countDown();}});}// 等待所有任务完成try {latch.await();} catch (InterruptedException e) {// 线程被中断,打印异常信息e.printStackTrace();}}

分割数据列表 partitionData 代码

   /*** 分割数据列表成多个小块。* @param dataList 待分割的数据列表,包含微信客户链接详情。* @param partitionSize 每个分区的大小。* @return 分割后的数据列表,每个元素是一个分区,分区内部保持原有顺序。*/private List<List<WechatCustomerLinkDetail>> partitionData(List<WechatCustomerLinkDetail> dataList, int partitionSize) {List<List<WechatCustomerLinkDetail>> partitions = new ArrayList<>();// 总数据量int size = dataList.size();// 每个分区的实际大小,整除操作保证每个分区大小尽量均匀int batchSize = size / partitionSize;// 遍历分区数量次,为每个分区添加数据for (int i = 0; i < partitionSize; i++) {// 当前分区的起始索引int fromIndex = i * batchSize;// 当前分区的结束索引,如果是最后一个分区,则包含所有剩余数据int toIndex = (i == partitionSize - 1) ? size : fromIndex + batchSize;// 将当前分区的数据添加到分区列表中partitions.add(dataList.subList(fromIndex, toIndex));}return partitions;}

到这里整个基于多线程处理数据的代码就整理完了,代码结构并不复杂,主要是注意数据查询以及服务器最大线程数相关数据,防止线程不够用的情况。

相关文章:

基于Java多线程处理数据

基于Java多线程处理数据 背景代码实现 背景 在日常工作中&#xff0c;有一个同步企微客户-学员关系接口的定时任务在执行中随着数据量的不断增长&#xff0c;定时任务的执行结束时间也出现了当天执行不完的情况&#xff0c;影响到了正常业务的运行。基于这种情况&#xff0c;在…...

日常知识点之遇到问题结构体按位构造协议时和期望不一致,研究记录一下

遇到一个问题&#xff0c;在做业务的时候&#xff0c;涉及到协议相关&#xff0c;按位进行设计&#xff0c;用结构体来模拟协议时&#xff0c;发现内存存储和实际目的不一致&#xff0c;知道是大小端以及计算机底层存储逻辑相关&#xff0c;所以研究了一下。 1&#xff1a;简单…...

spring mvc 文件下载

在web中下载的方式大多基于servlet&#xff0c;在web.xml中配置下载路径&#xff0c;这里再介绍json(转成base64字符串)和blob的使用方式 servlet WEB-INF/web.xml <!--url映射--> <servlet-mapping><servlet-name>DowloadServlet</servlet-name>&l…...

Qt WebEngine基于WebEngineScript注入js脚本

在之前的文章中&#xff0c;我们介绍了Qt WebEngine注入js的用法&#xff0c;及runJavaScript()的用法&#xff0c;该方法主要是用在页面加载完成后&#xff0c;为了和网页做一些交互时使用。有时候需要监听网页加载完成的一些状态或信息&#xff0c;则需要网页加载前注入js来实…...

案例分享-国外UI设计界面赏析

国外UI设计倾向于简洁的布局和清晰的排版&#xff0c;减少视觉干扰&#xff0c;提升用户体验。通过合理的色彩搭配和图标设计&#xff0c;营造舒适愉悦的使用氛围。 设计师不拘泥于传统框架&#xff0c;勇于尝试新元素和理念&#xff0c;使界面独特有趣。同时&#xff0c;强调以…...

用PyTorch 从零开始构建 BitNet 1.58bit

我们手动实现BitNet的编写&#xff0c;并进行的一系列小实验证实&#xff0c;看看1.58bit 模型是否与全精度的大型语言模型相媲美&#xff01; 什么是量化以及为什么需要它&#xff1f; 量化是用更少的比特数表示浮点数的过程。当两个数字使用不同的比特数进行量化时&#xf…...

信创安全 | 新一代内网安全方案—零信任沙盒

在当今数字化时代&#xff0c;访问安全和数据安全成为企业面临的重要挑战。传统的边界防御已经无法满足日益复杂的内网办公环境&#xff0c;层出不穷的攻击手段已经让市场单一的防御手段黔驴技穷。当企业面临越来越复杂的网络威胁和数据泄密风险时&#xff0c;更需要一种综合的…...

Redis的回收策略(淘汰策略)

volatile-lru &#xff1a;从已设置过期时间的数据集&#xff08; server.db[i].expires &#xff09;中挑选最近最少使用的数据淘汰 volatile-ttl &#xff1a; 从已设置过期时间的数据集&#xff08; server.db[i].expires &#xff09; 中挑选将要过期的数据淘汰 volatile…...

Electron-builder 打包

项目比较简单&#xff0c;仅使用了 Electron 原生js 安装 electron-builder npm install electron-builder --dev配置 package.json 中的打包命令 {"script":{// ..."dev": "electron .","pack": "electron-builder"} }添…...

笔试练习day3

目录 BC149 简写单词题目解析代码 dd爱框框题目解析解析代码方法一暴力解法方法二同向双指针(滑动窗口) 除2!题目解析解法模拟贪心堆 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 &#x1f412;&#x1f412;&#x1f412; 个人主页 &#x1f978;&#x1…...

企业想要将大模型技术应用到企业管理中需具备什么条件?

#企业 #企业管理 #大模型 企业想要将大模型技术应用到企业管理中&#xff0c;需要考虑以下几个关键条件&#xff1a; 1.明确的需求定位&#xff1a;企业应首先诊断自身的业务场景、数据、算法、基础设施预算以及战略等能力&#xff0c;明确大模型能够为企业带来的具体赋…...

go 事件机制(观察者设计模式)

背景&#xff1a; 公司目前有个业务&#xff0c;收到数据后&#xff0c;要分发给所有的客户端或者是业务模块&#xff0c;类似消息通知这样的需求&#xff0c;自然而然就想到了事件&#xff0c;观察者比较简单就自己实现以下&#xff0c;确保最小功能使用支持即可&#xff0c;其…...

RISC-V竞赛|第二届 RISC-V 软件移植及优化锦标赛报名正式开始!

目录 赛事背景 赛道方向 适配夺旗赛 优化竞速赛 比赛赛题&#xff08;总奖金池8万元&#xff01;&#xff09; &#x1f525;竞速赛 - OceanBase 移植与优化 比赛赛程&#xff08;暂定&#xff09; 赛事说明 「赛事背景」 为了推动 RISC-V 软件生态更快地发展&#xff0…...

【VTK】ubuntu手动编译VTK9.3 Generating qmltypes file 失败

环境 硬件&#xff1a;Jetson Xavier NX 套件 系统&#xff1a;Ubuntu 20.04 软件 &#xff1a;QT5.15.6 解决 0、问题 最近在Jetson Xavier NX 套件上编译VTK库&#xff0c;因为想要配合QQuick使用&#xff0c;所以cmake配置时勾选了VTK_MODULE_ENABLE_VTK_GUISupportQtQu…...

学习java的日子 Day64 学生管理系统 web2.0 web版本

MVC设计模式 概念 - 代码的分层 MVC&#xff1a;项目分层的思想 字母表示层理解MModle模型层业务的具体实现VView视图层展示数据CController控制器层控制业务流程&#xff08;跳转&#xff09; 1.细化理解层数 Controller&#xff1a;控制器层&#xff0c;用于存放Servlet&…...

【第14章】Spring Cloud之Gateway路由断言(IP黑名单)

文章目录 前言一、内置路由断言1. 案例&#xff08;Weight&#xff09;2. 更多断言 二、自定义路由断言1. 黑名单断言2. 全局异常处理3. 应用配置4. 单元测试 总结 前言 Spring Cloud Gateway可以让我们根据请求内容精确匹配到对应路由服务,官方已经内置了很多路由断言,我们也…...

3、pnpm yarn npm

项目里实际上就只有这些依赖 node module 里却有很多的包 原因&#xff1a; 比如说vue&#xff0c;vue内部有依赖了其余的包。工具又依赖了别的依赖 造成的问题&#xff1a;我可以直接去用这个包&#xff0c;但是这个包在package.json中却没有看到-----幽灵依赖 那如果说别…...

❄️5. Kubernetes核心资源之名称空间和Pod实战

**什么是名称空间Namespace: ** Namespace是k8s系统中的一种非常重要资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多用户的资源隔离。默认情况下&#xff0c;k8s集群中的所有的Pod都是可以相互访问的。但是在实际中&#xff0c;可能不想让两个Pod之间进行互…...

锂电池充电板电路设计

写这篇文章的目的主要是个人经验的总结&#xff0c;希望能给开发者们提供一种锂电池充电电路以及电源显示的电路思路。接下来从以下几个方面讲述电路。 设计这款电路的初衷是想用一块硬币大小的锂电池作为供电电源&#xff08;3.5V-4.2V&#xff09;&#xff0c;降压供给3.3V电…...

工业互联网产教融合实训基地解决方案

一、引言 随着“中国制造2025”战略的深入实施与全球工业4.0浪潮的兴起&#xff0c;工业互联网作为新一代信息技术与制造业深度融合的产物&#xff0c;正引领着制造业向智能化、网络化、服务化转型。为培养适应未来工业发展需求的高素质技术技能人才&#xff0c;构建工业互联网…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...