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

多个线程处理不同的数据,等线程都完成后再进行下一步操作

现在有三个任务,三个任务之间没有关联关系,但是第四个任务要等前三个完成之后才能进行,于是使用多线程完成前三个任务节省时间

示例代码:

public void saveDataByOnlineTimeNew(LocalDateTime startTime, LocalDateTime endTime) {Objects.requireNonNull(startTime, "开始时间不能为空");Objects.requireNonNull(endTime, "结束时间不能为空");List<User> users = baseMapper.selectAllRightUser(startTime, endTime);if (users.isEmpty()) {return;}List<Integer> userIdList = users.stream().map(User::getId).collect(Collectors.toList());// 创建三个 CompletableFuture 分别处理三个列表CompletableFuture<List<ProUserStatisticsNew>> future1 = CompletableFuture.supplyAsync(() -> {List<ProUserStatisticsNew> proUserStatisticsNews = saveDataByOnlineTime(startTime, endTime, userIdList);users.parallelStream().forEach(user -> {log.trace("当前线程名字:"+Thread.currentThread().getName());List<ProUserStatisticsNew> versionNotInRelationList = this.saveDataByOnlineTimeByUser(startTime, endTime, user);if (!versionNotInRelationList.isEmpty()) {proUserStatisticsNews.addAll(versionNotInRelationList);}});return proUserStatisticsNews;});CompletableFuture<List<ProUserStatisticsNew>> future2 = CompletableFuture.supplyAsync(() -> saveNoVersionDataByOnlineTime(startTime, endTime, userIdList));CompletableFuture<List<ProUserStatisticsNew>> future3 = CompletableFuture.supplyAsync(() -> saveLearnDataByOnlineTime(startTime, endTime, userIdList));// 等待所有 CompletableFuture 完成CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);// 等待所有 CompletableFuture 完成后,进行合并操作CompletableFuture<List<ProUserStatisticsNew>> join = allFutures.thenApplyAsync(v ->mergeLists(future1.join(), future2.join(), future3.join()));List<ProUserStatisticsNew> result = join.join();//List<ProUserStatisticsNew> result = mergeLists(proUserStatisticsNews, noVersionDataList, learnDataList);SysConfigTime sysConfigTimeByTime = SysConfigTimeUtil.getSysConfigTimeByTimeForQuery(endTime);result.parallelStream().forEach(one -> {one.setRecordDate(sysConfigTimeByTime.getYearmonth());one.setProjectHoursDifference(one.getWorkHours().subtract(one.getActualHours()));});// 批量保存或更新int batchSize = 100; // 根据具体要求和系统能力设置适当的批处理大小for (int i = 0; i < result.size(); i += batchSize) {int end = Math.min(result.size(), i + batchSize);this.saveOrUpdateBatch(result.subList(i, end));}}

代码解析:

这段代码实现了一个方法 `saveDataByOnlineTimeNew`,它通过多个异步任务(使用 `CompletableFuture`)并行处理数据,并最终将结果批量保存或更新到数据库中。具体的逻辑流程可以分为几个部分,下面我会逐步解释每个部分。### 方法说明- **输入参数**: `startTime` 和 `endTime` 是查询的开始和结束时间(`LocalDateTime` 类型),指定了需要查询的数据范围。- **核心目标**: 这个方法的目标是根据 `startTime` 和 `endTime` 获取相关数据,并将结果合并后保存或更新到数据库。### 代码分析1. **非空检查**:```javaObjects.requireNonNull(startTime, "开始时间不能为空");Objects.requireNonNull(endTime, "结束时间不能为空");```这两行代码确保 `startTime` 和 `endTime` 不能为空。如果为 `null`,将抛出 `NullPointerException`,并带有指定的错误信息。2. **获取用户列表**:```javaList<User> users = baseMapper.selectAllRightUser(startTime, endTime);if (users.isEmpty()) {return;}```这里通过调用 `baseMapper.selectAllRightUser(startTime, endTime)` 查询所有符合条件的用户。如果查询结果为空,则直接返回,不进行后续处理。3. **获取用户 ID 列表**:```javaList<Integer> userIdList = users.stream().map(User::getId).collect(Collectors.toList());```使用 `stream` 获取所有用户的 ID,方便后续操作。4. **创建多个 `CompletableFuture`**:```javaCompletableFuture<List<ProUserStatisticsNew>> future1 = CompletableFuture.supplyAsync(() -> {// 异步任务1});CompletableFuture<List<ProUserStatisticsNew>> future2 = CompletableFuture.supplyAsync(() -> saveNoVersionDataByOnlineTime(startTime, endTime, userIdList));CompletableFuture<List<ProUserStatisticsNew>> future3 = CompletableFuture.supplyAsync(() -> saveLearnDataByOnlineTime(startTime, endTime, userIdList));```创建了三个异步任务,每个任务执行不同的操作:- **`future1`**:调用 `saveDataByOnlineTime` 来保存基于在线时间的数据,然后对每个用户并行处理数据,并将结果合并。- **`future2`**:调用 `saveNoVersionDataByOnlineTime` 来保存没有版本数据的数据。- **`future3`**:调用 `saveLearnDataByOnlineTime` 来保存学习数据。5. **等待所有异步任务完成**:```javaCompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);```使用 `CompletableFuture.allOf()` 来等待所有的 `future1`, `future2`, `future3` 完成。`allOf` 返回一个 `CompletableFuture<Void>`,表明所有任务已完成。6. **合并结果**:```javaCompletableFuture<List<ProUserStatisticsNew>> join = allFutures.thenApplyAsync(v ->mergeLists(future1.join(), future2.join(), future3.join()));```当所有的异步任务完成后,调用 `thenApplyAsync` 继续处理合并操作。`join` 方法会阻塞直到每个 `CompletableFuture` 返回结果,合并三个任务的结果列表。7. **结果后处理**:```javaList<ProUserStatisticsNew> result = join.join();SysConfigTime sysConfigTimeByTime = SysConfigTimeUtil.getSysConfigTimeByTimeForQuery(endTime);result.parallelStream().forEach(one -> {one.setRecordDate(sysConfigTimeByTime.getYearmonth());one.setProjectHoursDifference(one.getWorkHours().subtract(one.getActualHours()));});```- `join.join()` 等待合并操作完成,获得最终的 `result` 列表。- 使用 `SysConfigTimeUtil.getSysConfigTimeByTimeForQuery(endTime)` 获取系统配置的时间信息。- 对 `result` 列表中的每一项,设置其记录日期(`setRecordDate`)和工作时间差(`setProjectHoursDifference`)。8. **批量保存或更新**:```javaint batchSize = 100;for (int i = 0; i < result.size(); i += batchSize) {int end = Math.min(result.size(), i + batchSize);this.saveOrUpdateBatch(result.subList(i, end));}```为了避免一次性将大量数据写入数据库,采用批处理的方式分批保存或更新数据。每次处理 `batchSize` 条记录(这里设定为100),直到所有记录处理完。### 关键点总结- **异步任务并行执行**:使用 `CompletableFuture.supplyAsync()` 创建三个并行任务来处理数据,从而加快整个处理过程。
- **合并操作**:通过 `thenApplyAsync` 合并三个异步任务的结果。
- **批量操作**:为了提高性能,使用批量保存或更新的方法 `saveOrUpdateBatch`,避免一次性提交过多数据。### 性能优化
- 该方法使用了并行流 (`parallelStream()`) 和异步执行(`CompletableFuture`),这些可以显著提升性能,尤其是对于大规模数据的处理。
- 批量操作减少了数据库访问的次数,提高了数据库的写入效率。总的来说,这段代码实现了一个高效的数据处理和保存机制,使用了现代 Java 特性(如异步编程和流操作)来优化性能。

相关文章:

多个线程处理不同的数据,等线程都完成后再进行下一步操作

现在有三个任务,三个任务之间没有关联关系,但是第四个任务要等前三个完成之后才能进行,于是使用多线程完成前三个任务节省时间 示例代码: public void saveDataByOnlineTimeNew(LocalDateTime startTime, LocalDateTime endTime) {Objects.requireNonNull(startTime, "开…...

聆听音乐 1.5.9 | 畅听全网音乐,支持无损音质下载

聆听音乐手机版是面向广大音乐爱好者的移动应用程序&#xff0c;用户可以随时随地通过手机享受丰富的音乐资源。它提供了多种魅力功能&#xff0c;让用户在手机上畅享更舒适的音乐体验&#xff0c;每位用户都能享受精彩纷呈的收听体验。此外&#xff0c;软件还支持无损音质音乐…...

Rust 基础入门指南

Rust 基础入门指南 1. Rust 语言概述 Rust 的历史与设计理念 Rust 是由 Mozilla 研究院的 Graydon Hoare 于2010年开始创建的系统编程语言。其设计目标是创建一种安全、并发、实用的编程语言&#xff0c;特别关注内存安全和并发性。 Rust 的核心设计理念包括&#xff1a; …...

青少年编程与数学 02-006 前端开发框架VUE 03课题、编写APP组件

青少年编程与数学 02-006 前端开发框架VUE 03课题、编写APP组件 一、组件二、VUE中的组件三、APP组件四、应用示例1. App.vue - 根组件2. HelloWorld.vue - 子组件3. main.js - 应用入口文件4. router/index.js - 路由配置文件5. index.html - HTML入口文件6. package.json - 项…...

基于Java的银行排号系统的设计与实现【源码+文档+部署讲解】

目 录 内容提要 1. 引言 2. 系统分析 2.1 系统初步调查 2.2 系统可行性分析 2.2.1 经济可行性 2.2.2 操作可行性 2.2.3 技术可行性 2.3 系统开发环境概述 2.3.1 硬件环境 2.3.2 软件环境 2.4 系统需求分析 2.4.1 业务流程分析 2.4.2 系统体系结构设计 2.4.3 系统逻辑模型 2.5 …...

linux-26 文件管理(四)install

说一个命令&#xff0c;叫install&#xff0c;man install&#xff0c;install是什么意思&#xff1f;安装&#xff0c;install表示安装的意思&#xff0c;那你猜install是用来干什么的&#xff1f;猜一猜干什么的&#xff1f;安装软件&#xff0c;安装第三方软件&#xff0c;错…...

VS2015中使用boost库函数时报错问题解决error C4996 ‘std::_Copy_impl‘

在VS2015中使用boost库函数buffer时遇到问题&#xff0c;其他函数定义均能执行&#xff0c;当加上bg::buffer(参数输入正确);语句后就报如下错误&#xff1a; 错误 C4996 std::_Copy_impl: Function call with parameters that may be unsafe - this call relies…...

pikachu靶场--目录遍历和敏感信息泄露

pikachu靶场—目录遍历和敏感信息泄露 目录遍历 概述 在web功能设计中,很多时候我们会要将需要访问的文件定义成变量&#xff0c;从而让前端的功能便的更加灵活。 当用户发起一个前端的请求时&#xff0c;便会将请求的这个文件的值(比如文件名称)传递到后台&#xff0c;后台再…...

植物大战僵尸杂交版3.0.2版本

更新内容 植物大战僵尸杂交版3.0.2版本的更新内容如下&#xff1a; • 修复BUG&#xff1a; • 游戏内贴图错乱的BUG。 • 无尽模式卡死的BUG。 • 卡牌模仿者的一系列BUG。 • 干扰车可能同时出现多辆的BUG。 • 冒险模式部分关卡无法过关的BUG。 • 新增内容&#xf…...

kafka怎么保证顺序消费?

kafka怎么保证顺序消费&#xff1f; 1. 分区内的顺序保证2. 并发消费3. 实现顺序消费的策略4. 注意事项 kafka创建 topic 的时候没有指定分区数量&#xff0c;那么默认只会有一个分区。如果你想要创建一个具有多个分区的 topic&#xff0c;你可以在创建 topic 的命令中指定 --p…...

Makefile 模板 --- 内核模块

内核模块模板 驱动源码同级目录下 #******************************************************************************* # xxx Co., Ltd. All Right Reserved. # Author : # Version : V1.0.0 2020.10.21 # Description : # Note : gaoyang3513163.co…...

仓库叉车高科技安全辅助设备——AI防碰撞系统N2024G-2

在当今这个高效运作、安全第一的物流时代&#xff0c;仓库作为供应链的中心地带&#xff0c;其安全与效率直接关系到企业的命脉。 随着科技的飞速发展&#xff0c;传统叉车作业模式正逐步向智能化、安全化转型&#xff0c;而在这场技术革新中&#xff0c;AI防碰撞系统N2024G-2…...

计算机视觉CV期末总复习

1.计算机视觉基础 数字图像表示 二值图像 仅包含黑白两种颜色的图像&#xff0c;只使用1个比特为&#xff08;0黑或1白&#xff09;表示 彩色图像&#xff1a;分不同的颜色空间 gray灰度图像 每个像素只有一个采样颜色&#xff0c;取值范围0--255&#xff0c;为8比特位&a…...

【微信小程序获取用户手机号

微信小程序获取用户手机号有2种,一种是前端自己解密,一种是获取后发给后端,后端去解密 重点:要在微信公众平台设置里面绑定微信开放平台账号,不然反解不出来用户手机号上代码: <button style"font-size: 16px;" open-type"getPhoneNumber" getphonenumb…...

WFP Listbox绑定数据后,数据变化的刷新

Listbox绑定数据通过ItemsSource来的&#xff0c;如果绑定的是普通的List<数据>&#xff0c;不会自己刷新。 使用ObservableCollection集合 解决问题的方法: 将数组替换为 ObservableCollection ObservableCollection 是专为绑定设计的集合类型&#xff0c;可以通知 W…...

Android Camera压力测试工具

背景描述&#xff1a; 随着系统的复杂化和业务的积累&#xff0c;日常的功能性测试已不足以满足我们对Android Camera相机系统的测试需求。为了确保Android Camera系统在高负载和多任务情况下的稳定性和性能优化&#xff0c;需要对Android Camera应用进行全面的压测。 对于压…...

【华为OD-E卷 - 最优资源分配 100分(python、java、c++、js、c)】

【华为OD-E卷 - 最优资源分配 100分&#xff08;python、java、c、js、c&#xff09;】 题目 某块业务芯片最小容量单位为1.25G&#xff0c;总容量为M*1.25G&#xff0c;对该芯片资源编号为1&#xff0c;2&#xff0c;…&#xff0c;M。该芯片支持3种不同的配置&#xff0c;分…...

字符串格式时间(HH-MM)添加间隔时间后转为HH-MM输出

转换时间代码如下所示 #include <iostream> #include <iomanip> #include <sstream>//添加时间转换为时间 std::string addMinutesToTime(const std::string& timeStr, int minutesToAdd) {int hours, minutes;char delimiter;//解析输入时间std::istri…...

SQL 基础教程 - SQL ORDER BY 关键字

SQL ORDER BY 关键字 ORDER BY 关键字用于对结果集进行排序。 SQL ORDER BY 关键字 ORDER BY 关键字用于对结果集按照一个列或者多个列进行排序。 ORDER BY 关键字默认按照升序对记录进行排序。如果需要按照降序对记录进行排序&#xff0c;您可以使用 DESC 关键字。 SQL ORD…...

STM32 软件I2C读写

单片机学习&#xff01; 目录 前言 一、软件I2C读写代码框架 二、I2C初始化 三、六个时序基本单元 3.1 引脚操作的封装和改名 3.2 起始条件执行逻辑 3.3 终止条件执行逻辑 3.4 发送一个字节 3.5 接收一个字节 3.5 发送应答&接收应答 3.5.1 发送应答 3.5.2 接…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准

城市路内停车管理常因行道树遮挡、高位设备盲区等问题&#xff0c;导致车牌识别率低、逃费率高&#xff0c;传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法&#xff0c;正成为破局关键。该设备安装于车位侧方0.5-0.7米高度&#xff0c;直接规避树枝遮…...