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

springboot 多线程实战

先说下业务场景,业务1:基于实时轨迹数据打卡,业务2:基于非实时轨迹的时间差,计算累计时长。 简单点说就是从websocket获取到的实时数据,既要兼容不耗时操作,又要兼容耗时操作。

单线程做的话,一两个用户的数据没问题,用户多了就处理不过来。

实现思路是用TaskExecutor来做,一个task接收从redis lPop的数据,并放入BlockingQueue,另外的task从BlockingQueue获取数据。

@Autowiredprivate TaskExecutor taskExecutor1;@Autowiredprivate TaskExecutor taskExecutor2;@Autowiredprivate TaskExecutor taskExecutor3;static BlockingQueue<TrackHistory> dataQueue = new ArrayBlockingQueue<>(1 << 12);static BlockingQueue<TrackHistory> keepWatchQueue = new ArrayBlockingQueue<>(1 << 12);public static final String M = ":";@Bean("redisReadThread")public String service() {taskExecutor1.execute(() -> {while (true) {try {lPop();} catch (Exception e) {e.printStackTrace();}}});return null;}@Bean("calculationsBusinessData")public void calculationsService() {taskExecutor2.execute(() -> {while (true) {try {if (dataQueue.size() != 0) {TrackHistory trackRealTime = dataQueue.poll();if (trackRealTime == null) {Thread.sleep(100L);} else {//耗时方法doSomething();//存储当前日期+人员的最新位置坐标saveTrackToRedis(trackRealTime);}} else {Thread.sleep(100L);}} catch (Exception e) {log.error("业务1数据计算异常->{}", e.getMessage());}}});}@Bean("calculationsKeepWatch")public void keepWatchService() {taskExecutor3.execute(() -> {while (true) {try {if (keepWatchQueue.size() != 0) {TrackHistory trackRealTime = keepWatchQueue.poll();if (trackRealTime == null) {Thread.sleep(100L);} else {doSomething2(trackRealTime);}} else {Thread.sleep(100L);}} catch (Exception e) {log.error("业务2数据计算异常->{}", e.getMessage());}}});}/*** 从队列中读取数据** @return*/private synchronized void lPop() {Object o = redisTemplate.opsForList().leftPop(RedisKeyCons.COORDINATE);if (!org.springframework.util.StringUtils.isEmpty(o)) {TrackHistory trackRealTime = (TrackHistory) o;log.info("leftPop trackHistory = {}", trackRealTime);if (null != trackRealTime) {if (checkMemberExist(trackRealTime)) {return;}//存储当前日期+人员的最新位置坐标saveTrackToRedisForKeepWatch(trackRealTime);dataQueue.add(trackRealTime);keepWatchQueue.add(trackRealTime);}}}

配置线程池

/*** 线程池配置、启用异步***/
@EnableAsync
@Configuration
public class AsycTaskExecutorConfig {@Bean(name="taskExecutor1")public TaskExecutor taskExecutor1() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();taskExecutor.setCorePoolSize(1);taskExecutor.setMaxPoolSize(1);return taskExecutor;}@Bean(name="taskExecutor2")public TaskExecutor taskExecutor2() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();//最大线程数taskExecutor.setMaxPoolSize(5);//核心线程数taskExecutor.setCorePoolSize(5);//任务队列的大小taskExecutor.setQueueCapacity(5);//线程前缀名
//        executor.setThreadNamePrefix();//线程存活时间taskExecutor.setKeepAliveSeconds(60);taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//线程初始化return taskExecutor;}@Bean(name="taskExecutor3")public TaskExecutor taskExecutor3() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();//最大线程数taskExecutor.setMaxPoolSize(5);//核心线程数taskExecutor.setCorePoolSize(5);//任务队列的大小taskExecutor.setQueueCapacity(5);//线程前缀名
//        executor.setThreadNamePrefix();//线程存活时间taskExecutor.setKeepAliveSeconds(60);taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//线程初始化return taskExecutor;}@Bean(name = "asyncPoolTaskExecutor")public ThreadPoolTaskExecutor executor() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();//核心线程数taskExecutor.setCorePoolSize(10);//线程池维护线程的最大数量,只有在缓冲队列满了之后才会申请超过核心线程数的线程taskExecutor.setMaxPoolSize(10);//缓存队列taskExecutor.setQueueCapacity(15);//设置线程的空闲时间,当超过了核心线程出之外的线程在空闲时间到达之后会被销毁taskExecutor.setKeepAliveSeconds(60);//异步方法内部线程名称taskExecutor.setThreadNamePrefix("async-");/*** 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略* 通常有以下四种策略:* ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。* ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。* ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)* ThreadPoolExecutor.CallerRunsPolicy:重试添加当前的任务,自动重复调用 execute() 方法,直到成功*/taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());taskExecutor.initialize();return taskExecutor;}}

相关文章:

springboot 多线程实战

先说下业务场景&#xff0c;业务1&#xff1a;基于实时轨迹数据打卡&#xff0c;业务2&#xff1a;基于非实时轨迹的时间差&#xff0c;计算累计时长。 简单点说就是从websocket获取到的实时数据&#xff0c;既要兼容不耗时操作&#xff0c;又要兼容耗时操作。 单线程做的话&a…...

求生之路2社区服务器sourcemod安装配置搭建教程centos

求生之路2社区服务器sourcemod安装配置搭建教程centos 大家好我是艾西&#xff0c;通过上文我们已经成功搭建了求生之路2的服务端。但是这个服务端是纯净的服务端&#xff0c;就是那种最纯粹的原版。如果想要实现插件、sm开头的命令等功能&#xff0c;需要安装这个sourcemod。…...

通达OAV12版本,表单及流程,定制开发总结

通达OA-V12版本&#xff0c;表单及流程&#xff0c;定制开发总结 触发器金蝶系统对接 日期&#xff1a;2023年8月29日 触发器 一键转交操作&#xff0c;不会调用触发器。 解决办法&#xff1a;可以按需要按步骤&#xff0c;关闭一键转交按钮。这里会隐藏一键转交、一键结束按钮…...

浅析Linux 物理内存外碎片化

本文出现的内核代码来自Linux4.19&#xff0c;如果有兴趣&#xff0c;读者可以配合代码阅读本文。 一、Linux物理内存外碎片化概述 什么是Linux物理内存碎片化&#xff1f;Linux物理内存碎片化包括两种&#xff1a; 1.物理内存内碎片&#xff1a;指分配给用户的内存空间中未…...

C#中的get和set

当我们定义属性的 get 访问器和 set 访问器时&#xff0c;其中的 return 和 value 分别代表以下含义&#xff1a; return&#xff1a;在 get 访问器中使用&#xff0c;表示返回属性的值给调用方。它用于将属性关联的字段的值返回给外部代码。value&#xff1a;在 set 访问器中…...

mysql8.0以上忘记密码的重置方法 - window系统

1、关闭 mysql 服务&#xff0c;以 管理员身份 运行命令提示符工具&#xff0c;执行下面的命令 net stop mysql可以在任务管理器的服务中查看状态 2、跳过 mysql 权限验证&#xff0c;以管理员身份运行 cmd&#xff0c;进入 mysql 的安装 bin 目录&#xff0c;执行如下指令 m…...

手写Vue3响应式数据原理

Vue3响应式数据 前言一、proxy是什么&#xff1f;1.1 proxy基本使用 二、实现最基本的reactive函数三、实现基本响应式系统四、完善基本响应式系统4.1 执行每一个副作用函数4.2 实现依赖收集4.2.1 基本实现 4.3 改进桶结构 五、相关面试题1.Object.defineProperty 和 Proxy 的区…...

基于PIC单片机篮球计分计时器

一、系统方案 本设计采用PIC单片机作为主控制器&#xff0c;矩阵键盘控制&#xff0c;比分&#xff0c;计时控制&#xff0c;24秒&#xff0c;液晶12864显示。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 2、液晶显示程序 /*************…...

关于Maxwell与Kafka和数据库的监控

1.Maxwell的配置 其实就是配置两端的配置信息,都要能连接上,然后才能去传输数据 config.properties #Maxwell数据发送目的地&#xff0c;可选配置有stdout|file|kafka|kinesis|pubsub|sqs|rabbitmq|redis producerkafka # 目标Kafka集群地址 kafka.bootstrap.servershadoop102…...

【设计模式】Java设计模式详细讲解

一、概述 Java设计模式是Java程序设计中一种重要的最佳实践&#xff0c;它提供了一种框架和结构&#xff0c;可以帮助开发者更好地理解和设计复杂的系统。设计模式不仅仅是一种语法规则&#xff0c;更是一种思想和方法论&#xff0c;它能够帮助开发者更好地分析、设计和实现软…...

【MySQL】表的增删查改(进阶)

目录 1.数据库约束 1.1NOT NULL&#xff1a;非空约束 1.2UNIQUE&#xff1a;唯一值约束 1.3DEFAULT&#xff1a;默认值约束 1.4PRIMARY KEY&#xff1a;主键约束 1.5FOREIGN KEY&#xff1a;外键约束 1.6CHECK约束 2.表的设计 2.1一对一 2.2一对多 2.3多对多 3.新增…...

Vim几种跳转方式

ps: 以下时我常用的一些跳转指令&#xff0c;用于参考和复习记忆。还有一些后续会更新。 文件内跳转 移动光标 普通模式下左h&#xff0c;右l&#xff0c;上k&#xff0c;下j。&#xff08;可以使用数字hlkj&#xff0c;实现跳跃式移动&#xff09;。 字符间跳转 …...

element-ui 弹窗里面嵌套弹窗,解决第二个弹窗被遮罩层掩盖无法显示的问题

当我们在 element-ui 中使用弹窗嵌套弹窗时&#xff0c;会出现第二个弹窗打开时被一个遮罩层挡着&#xff0c;就像下面这样&#xff1a; 下面提供两种解决方案 &#xff1a; 一、第一种方案 我们查询element-ui 官网可以发现 el-dialog 有这样几个属性&#xff1a; 具体使用就…...

【业务功能篇76】微服务网关路由predicates断言条件-filters路由转换地址-跨域问题-多级目录树化层级设计-mybatisPlus逻辑删除

业务开发-基础业务-分类管理 启动renren-fast如果出现如下错误 -Djps.track.ap.dependenciesfalse 添加相关配置即可 分类管理 1.后端分类接口 JDK8特性&#xff1a;https://blog.csdn.net/qq_38526573/category_11113126.html 在后端服务中我们需要查询出所有的三级分类信…...

apache的ab工具测试网页优化效果速度以及服务器承载

今天为大家介绍一款apache自带的一种的测试网页优化效果速度以及服务器承载的工具——ab.exe。 大家在工作中或者开发中可以使用apache的ab工具来测试自己的网站并发量大小&#xff0c;和某个页面的访问时间。 一、基本用法 如果你是用的是apache的话&#xff0c;那么只要进…...

【进阶篇】MySQL 存储引擎详解

文章目录 0.前言1.基础介绍2.1. InnoDB存储引擎底层原理InnoDB记录存储结构和索引页结构InnoDB记录存储结构&#xff1a;InnoDB索引页结构&#xff1a; 3. MVCC 详解3.1. 版本号分配&#xff1a;3.2. 数据读取&#xff1a;3.3. 数据写入&#xff1a;3.4. 事务隔离级别&#xff…...

Spring集成【MyBatis】和【PageHelper分页插件】整合---详细介绍

一&#xff0c;spring集成Mybatis的概念 Spring 整合 MyBatis 是将 MyBatis 数据访问框架与 Spring 框架进行集成&#xff0c;以实现更便捷的开发和管理。在集成过程中&#xff0c;Spring 提供了许多特性和功能&#xff0c;如依赖注入、声明式事务管理、AOP 等 它所带来给我们的…...

PyCharm下安装配置PySide6开发环境(Qt Designer(打开,编辑)、PyUIC和PyRCC)

一.准备工作 1.安装python和pycharm并配置好环境变量 python安装路径 pycharm安装路径&#xff1a; python系统变量&#xff1a; pycharm环境变量&#xff1a; 注意&#xff1a;正常安装&#xff0c;并勾选ADD PATH一般会自动配好 2.在pycharm创建一个新的python的虚拟环境 …...

pytest fixture 创建一个 requests.session() 对象

当你运行这段代码时&#xff0c;它会执行以下操作&#xff1a; 1. 导入必要的库&#xff1a;pytest 和 requests。 2. 定义一个夹具&#xff08;fixture&#xff09;函数 session&#xff0c;使用 pytest.fixture(scopesession) 装饰器进行标记。这个夹具函数在整个测试会话期…...

深入分析负载均衡情景

本文出现的内核代码来自Linux5.4.28&#xff0c;为了减少篇幅&#xff0c;我们尽量不引用代码&#xff0c;如果有兴趣&#xff0c;读者可以配合代码阅读本文。 一、有几种负载均衡的方式&#xff1f; 整个Linux的负载均衡器有下面的几个类型&#xff1a; 实际上内核的负载均衡…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

自然语言处理——文本分类

文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益&#xff08;IG&#xff09; 分类器设计贝叶斯理论&#xff1a;线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别&#xff0c; 有单标签多类别文本分类和多…...