【JAVA】利用Redisson和Spring实现高效物联温度控制链路,确保温度调节的准确性和效率,定时链路执行使用案例,一环扣一环

主要功能和场景

  1. 柔性调温策略:这个类主要用于管理一个温度调节流程,通过不同的策略(如策略1和策略2)来调节温度,确保设备或环境中的温度达到预设的目标。

  2. 紧急停止机制:在流程执行过程中,如果需要紧急停止,可以通过设置一个标志来立即停止所有正在进行的任务。

  3. 定时任务管理:使用Java的ScheduledExecutorService来管理定时任务,如定期检查温度、执行特定的温度调节策略等。

  4. Redis集成:使用Redisson客户端与Redis数据库交互,存储和检索紧急停止的状态。

代码详细描述

  • 类结构

    • 使用@Slf4j注解来自动生成日志记录器。
    • 使用@RequiredArgsConstructor注解来自动注入对象
  • 常量定义

    • STRATEGY_DURATION:定义了策略的持续时间,这里是5分钟减去30秒。
    • EMERGENCY_STOPPED_KEY:在Redis中存储紧急停止状态的键。
    • EMERGENCY_STOPPEDRESTART_STOPPED:分别代表紧急停止和重启的状态。
  • 方法

    • startProcessChain(Long planId):启动整个流程,首先检查是否需要紧急停止,然后开始执行柔性调温策略1。
    • applyFlexibleTempStrategy1(Long planId)applyFlexibleTempStrategy2(Long planId):分别实现策略1和策略2,包括下发温度调节指令和召测命令,以及根据召测结果调整策略。
    • waitFor5MinutesAfterStrategy1(Long planId)waitFor10MinutesAfterStrategy2(Long planId):在策略1和策略2之后等待一定时间,然后执行下一步。
    • applyTargetPower(Long planId):在策略2之后执行目标功率控制。
    • waitFor10MinutesBeforeStop(Long planId):在停止前等待10分钟。
    • emergencyStop(Long planId)restart(Long planId):分别用于紧急停止流程和重启流程。
    • isEmergencyStopped(Long planId)setEmergencyStopped(Long planId):用于检查和设置紧急停止状态。

使用场景

这个类适用于需要精确控制温度的场景,如数据中心、实验室或工业生产环境,其中温度的精确控制对于设备的正常运行至关重要。通过这个流程管理器,可以确保在各种情况下都能有效地调节温度,同时提供紧急停止机制以应对突发情况。

ProcessManager类中,每个流程都创建了一个ScheduledExecutorService实例,通过Executors.newScheduledThreadPool(1)创建了一个大小为1的线程池。这种设计有几个好处:

  1. 资源控制:通过限制线程池的大小为1,可以确保每个流程在其生命周期内只使用一个线程。这有助于防止资源过度消耗,特别是在高并发环境中,可以避免因创建过多线程而导致的系统资源耗尽。

  2. 任务串行执行:由于线程池大小为1,所有提交给该线程池的任务将按顺序串行执行。这意味着一个流程中的所有任务都是顺序执行的,不会并发执行,这有助于简化任务之间的同步和数据依赖问题。

  3. 简化同步:在某些情况下,流程中的任务可能需要访问共享资源或状态,串行执行可以减少或消除对这些资源进行复杂同步的需求,因为任务不会并发地访问这些资源。

  4. 避免竞态条件:在单线程环境中,不会出现竞态条件(race conditions),因为任务是按顺序执行的。这对于确保流程的正确性和可预测性非常重要。

  5. 易于管理:单线程池使得任务的管理和监控更加简单。例如,如果需要取消所有任务,只需调用scheduler.shutdown()即可。

  6. 适合定时任务ScheduledExecutorService特别适合执行定时任务,如周期性任务或延迟任务。通过使用单线程池,可以确保这些任务按照预定的时间表执行,而不会因为线程争用而产生时间偏差。

总之,为每个流程创建一个单线程的ScheduledExecutorService可以提供一个简单、可控且高效的方式来管理流程中的定时任务,同时确保流程的稳定性和可预测性。

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.text.CharSequenceUtil;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;/*** 能力认定流程manager*/
@Slf4j
@Component
@RequiredArgsConstructor
public class ProcessManager {/*** 5分钟,单位为毫秒(策略持续时间),30秒执行一次,减少30秒是由于第一次进入默认执行一次召测*/private static final long STRATEGY_DURATION = 5 * 60 * 1000 - 30000;/*** Redis中存储紧急停止值*/private static final String EMERGENCY_STOPPED_KEY = "IOT:EMERGENCY:STOPPED:VAL:";/*** 紧急停止值*/private static final String EMERGENCY_STOPPED = "1";/*** 重启*/private static final String RESTART_STOPPED = "0";/*** Redisson客户端*/private final RedissonClient redissonClient;/*** 启动任务*/public void startProcessChain(Long planId) {// 否紧急停止if (isEmergencyStopped(planId)) {return;}ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);log.info("Step 0 startProcessChain with task ID: " + planId);// 立即执行柔性调温策略1scheduler.schedule(() -> applyFlexibleTempStrategy1(planId), 0, TimeUnit.SECONDS);// 立马取消当前任务scheduler.shutdown();}/*** 柔性调温策略1*/private void applyFlexibleTempStrategy1(Long planId) {// 紧急停止if (isEmergencyStopped(planId)) {return;}log.info("Step 1 下发遥调指令task ID: " + planId);// 下发遥调指令String tempValue = "18";// 下发遥调任务失败,流程结束if (packageCommandTempIssuance()) {return;}long startTime = System.currentTimeMillis();// 整个流程持续五分钟,30秒执行一次ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);scheduler.scheduleAtFixedRate(() -> {// 紧急停止if (isEmergencyStopped(planId)) {return;}log.info("Step 1 下发召测命令 task ID: " + planId);int unConformNum = packageCallForTest();// 不满足数量=0时表示都满足18° ± 0.5°,立即执行下一步if (unConformNum == 0) {log.info("Step 1 策略1条件已满足,执行下一步等待 task ID: " + planId);// 满足条件立马执行:"等待五分钟"策略scheduler.schedule(() -> waitFor5MinutesAfterStrategy1(planId), 0, TimeUnit.SECONDS);// 立马取消当前任务scheduler.shutdown();}long elapsedTime = System.currentTimeMillis() - startTime;// 5分钟内所有通道温度未达到18° ± 0.5°,任务终止if (unConformNum != 0 && elapsedTime >= STRATEGY_DURATION) {log.info("Step 1 下发召测命令不满足要求:planId:{},不满足数量:{} ", planId, unConformNum);emergencyStop(planId);scheduler.shutdown();}}, 0, 30, TimeUnit.SECONDS);}/*** 柔性调温策略1之后等待五分钟:配置码值动态获取*/private void waitFor5MinutesAfterStrategy1(Long planId) {// 紧急停止if (isEmergencyStopped(planId)) {return;}String value = "5";log.info("After step 1 waiting for " + value + " minutes for task ID: " + planId);ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);// 五分钟之后执行applyFlexibleTempStrategy2scheduler.schedule(() -> applyFlexibleTempStrategy2(planId), Long.parseLong(value),TimeUnit.MINUTES);// 立马取消当前任务scheduler.shutdown();}/*** 柔性调温策略2*/private void applyFlexibleTempStrategy2(Long planId) {// 紧急停止if (isEmergencyStopped(planId)) {return;}log.info("Step 2 策略2下发遥调指令 task ID: " + planId);// 下发遥调指令String tempValue = "26";// 下发遥调任务失败,流程结束if (packageCommandTempIssuance()) {emergencyStop(planId);return;}long startTime = System.currentTimeMillis();// 整个流程持续五分钟ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);scheduler.scheduleAtFixedRate(() -> {// 紧急停止if (isEmergencyStopped(planId)) {return;}log.info("Step 2 策略2下发召测指令 task ID: " + planId);int unConformNum = packageCallForTest();// 不满足数量=0时表示都满足26° ± 0.5°,立即执行下一步if (unConformNum == 0) {log.info("Step 2 策略2条件已满足,执行下一步等待 task ID: " + planId);// 满足条件立马执行:"等待五分钟"策略scheduler.schedule(() -> waitFor10MinutesAfterStrategy2(planId), 0, TimeUnit.SECONDS);// 立马取消当前任务scheduler.shutdown();}long elapsedTime = System.currentTimeMillis() - startTime;// 5分钟内所有通道温度未达到26° ± 0.5°,任务终止if (unConformNum != 0 && elapsedTime >= STRATEGY_DURATION) {log.info("Step 2 下发召测命令不满足要求:planId:{},不满足数量:{} ", planId, unConformNum);emergencyStop(planId);// 立马取消当前任务scheduler.shutdown();}}, 0, 30, TimeUnit.SECONDS);}/*** 柔性调温策略2之后等10分钟:配置码值动态获取*/private void waitFor10MinutesAfterStrategy2(Long planId) {if (isEmergencyStopped(planId)) {return;}String value = "10";log.info("After step 2 Waiting for " + value + " minutes task: " + planId);ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);// 等10分钟目标功率控制scheduler.schedule(() -> applyTargetPower(planId), Long.parseLong(value), TimeUnit.MINUTES);// 立马取消当前任务scheduler.shutdown();}/*** 目标功率控制*/private void applyTargetPower(Long planId) {if (isEmergencyStopped(planId)) {return;}log.info("Step 3 目标功率控制 task ID: " + planId);// 下发遥调任务失败,流程结束if (packageCommandTempIssuance()) {emergencyStop(planId);return;}ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);// 立即执行停止前等待10分钟scheduler.schedule(() -> waitFor10MinutesBeforeStop(planId), 0,TimeUnit.SECONDS);// 立马取消当前任务scheduler.shutdown();}/*** 停止前等待10分钟:配置码值动态获取*/private void waitFor10MinutesBeforeStop(Long planId) {// 紧急停止if (isEmergencyStopped(planId)) {return;}String tempValue = "10";log.info("After step 3 wait for " + tempValue + " minutes task ID: " + planId);ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);scheduler.schedule(() -> {log.info("waitFor10MinutesBeforeStop step 4 stop task ID: " + planId);// 立马取消当前任务scheduler.shutdown();}, Long.parseLong(tempValue), TimeUnit.MINUTES);}/*** 紧急停止*/public void emergencyStop(Long planId) {log.info("Emergency stopping the process with task ID: " + planId);setEmergencyStopped(planId);}/*** 重启一键能力认证流程*/public void restart(Long planId) {// 1:true,0:falseredissonClient.getBucket(EMERGENCY_STOPPED_KEY + planId).set(RESTART_STOPPED);}/*** 是否紧急停止*/private boolean isEmergencyStopped(Long planId) {RBucket < String > bucket = redissonClient.getBucket(EMERGENCY_STOPPED_KEY + planId);String isEmergencyStopped = bucket.get();return isEmergencyStopped != null && CharSequenceUtil.equals(isEmergencyStopped, EMERGENCY_STOPPED);}/*** 设置紧急停止值*/private void setEmergencyStopped(Long planId) {// 1:true,0:falseredissonClient.getBucket(EMERGENCY_STOPPED_KEY + planId).set(EMERGENCY_STOPPED);}/*** 下发遥调指令*/private boolean packageCommandTempIssuance() {// 下发遥调指令,示意代码return true;}/*** 下发召测命令** @return 不满足数量*/private Integer packageCallForTest() {// 下召测命令,拿内机数据,示意代码return 0;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI模型大宗师Transformer的Encoder魔法棒

在AI大模型数字王国里&#xff0c;有一位名叫Transformer的魔法大宗师。他有一个神奇的百宝箱&#xff0c;里面有很多魔法工具&#xff0c;其中有个工具叫Encoder&#xff0c;这个工具拥有一种神奇的力量&#xff0c;可以将复杂的输入信息进行编码&#xff0c;提取出关键的特征…

以 Vue 3 项目为例,你是否经常遇到 import 语句顺序混乱的问题?要想解决它其实很容易!

大家好,我是CodeQi! 在项目开发过程中,我们经常会遇到项目中的 import 语句顺序混乱的问题。 这不仅会影响代码的可读性,还可能使我们代码在提交的时候产生不必要的冲突。 面对这种情况,要想解决它其实很容易。 通过合理的规范和自动化工具,我们可以确保 import 语句…

计算机网络 —— 路由协议:RIP、OSPF、BGP、MPLS

路由协议 1. 定义2. IGP2.1 RIP2.2 OSPF 3. BGP4. MPLS 1. 定义 互联网中需要通过路由将数据发送至目标主机。 路由器根据路由控制表(RoutingTable)转发数据包&#xff0c;它根据所收到的数据包中目标主机的IP地址与路由控制表的比较得出下一个应该接收的路由器。 &#xff…

大学生放学后一定要做的4件事情

不知道有多少学生们&#xff0c;和我当年一样&#xff0c;上课不想去&#xff0c;找人帮着点名。放学后&#xff0c;去网吧&#xff0c;瞎玩&#xff0c;玩着玩着就毕业了&#xff0c;现在想想啊&#xff0c;真是不应该。所以&#xff0c;下面这4件事情&#xff0c;我建议你去做…

Linux/Unix命令

这篇是另一篇内容的前置知识。因为项目部署测试需要&#xff0c;向公司申请了一个虚拟机做服务器用。以下是回溯的命令&#xff0c;多了解了解&#xff0c;拓宽知识面吧。PS&#xff1a;本人unix/linux知识0&#xff0c;见啥都稀奇&#xff0c;小白一个&#xff0c;知识浅显&am…

CSharp——Encoding编码详情

CSharp-Encoding编码 在网络通信中&#xff0c;很多情况下都是将字符信息转成字节序列进行传输。将字符序列转为字节序列的过程称为编码。当这些字节传送到接收方&#xff0c;接收方需要逆向将字节序列转为字符序列。这个过程就是解码。 常见编码有ASCII字符集 &#xff0c;非…

SQL | join 的目的是什么?

如是我闻&#xff1a; 在 SQL 中使用 JOIN 的目的是将两个或多个数据库表的数据组合在一起&#xff0c;这样我们就可以在一个查询中获取这些表的相关信息。 假设我们有两本不同的书&#xff0c;一本记录了孩子们的名字和他们的爱好&#xff0c;另一本记录了他们的家庭地址。如…

盛元广通打造智慧校园实验室安全管理系统

盛元广通智慧校园实验室安全管理系统以安全为重点&#xff0c;构建由学校、二级单位、实验室组成的三级联动的实验室安全多级管理体系、多类用户角色&#xff0c;内置教育部标准检查表&#xff0c;支撑实验室相关业务过程的智慧管理。实现通过PC端/手机移动端开展检查工作、手机…

sh脚本笔记2

test条件测试 语法 条件测试语法说明语法1&#xff1a;test <测试表达式>这是利用test命令进行条件测试表达式的方法。test命令和“<测试表达式>”之间至少有一个空格语法2&#xff1a;[ <测试表达式> ]这是通过[]&#xff08;单中括号&#xff09;进行条件…

将exe文件添加到注册表中,实现开机时自动运行

目录 一、前言 二、代码 三、使用步骤 1.编译生成exe文件、 2.以管理员身份运行代码 3.打开注册表&#xff0c;验证结果 一、前言 在Windows操作系统中&#xff0c;将exe文件的路径添加到注册表下&#xff0c;主要用于实现程序的开机自动运行功能。 注册表路径为&#xf…

白骑士的C语言教学基础篇 1.3 控制流

系列目录 上一篇&#xff1a;白骑士的C语言教学基础篇 1.2 C语言基础语法 在这一节中&#xff0c;我们将介绍C语言中的控制流结构&#xff0c;包括条件语句、循环语句以及循环控制语句。这些结构允许我们根据不同的条件执行不同的代码块&#xff0c;从而使程序更具灵活性和功能…

Python中的并发编程(5)PyQt 多线程

PyQt 多线程 1 卡住的计时器 我们定义了一个计时器&#xff0c;每秒钟更新一次显示的数字。此外我们定义了一个耗时5秒的任务oh_no&#xff0c;和按钮“危险”绑定。 当我们点击“危险”按钮时&#xff0c;程序去执行oh_no&#xff0c;导致显示停止更新了。 import sys im…

Aspose.PDF功能演示:在程序中合并 JPG 文件

Aspose.PDF 是一款高级PDF处理API&#xff0c;可以在跨平台应用程序中轻松生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现&#xff0c;保护和打印文档。无需使用Adobe Acrobat。此外&#xff0c;API提供压缩选项&#xff0c;表创建和处理&#xff0c;图形和图像功能&am…

Kile钟优化等级讲解

这里直接说说kile的优化等级: 这里有4个等级,分别为:-O0、-O1、-O2、-O3 为什么要进行编译优化? 主要目的: 1. 提高代码执行的速度; 2. 减少内存占用; 3. 降低能耗,延长电池寿命; 4. 消除代码中冗余和不必要的代码,提高程序稳定性和可靠性。 Kile等级描述: -O0:这…

leetcode-21-回溯-全排列及其去重

一、[46]全排列 给定一个 没有重复 数字的序列&#xff0c;返回其所有可能的全排列。 示例: 输入: [1,2,3]输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 其中&#xff0c;不需要使用startIndex used数组&#xff0c;其实就是记录此时path里都有哪些元素…

【图论】200. 岛屿问题

200. 岛屿问题 难度&#xff1a;中等 力扣地址&#xff1a;https://leetcode.cn/studyplan/top-100-liked/ 问题描述 给你一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&…

一个专为Android平台设计的高度可定制的日历库

大家好&#xff0c;今天给大家分享一个高度可定制的日历库kizitonwose/Calendar。 Calendar专为Android平台设计&#xff0c;支持RecyclerView和Compose框架。它提供了丰富的功能&#xff0c;允许开发者根据需求定制日历的外观和功能。 项目介绍 此库是开发Android应用时&…

大型语言模型评估调查

原文链接&#xff1a;A Survey on Evaluation of Large Language Models | ACM Transactions on Intelligent Systems and Technology 本文从三个关键维度&#xff1a;评价什么、在哪里评价和如何评价&#xff0c;对这些 LLMs 评价方法进行了全面回顾。 首先&#xff0c;我们…

第十四届蓝桥杯省赛C++A组F题【买瓜】题解(AC)

70pts 题目要求我们在给定的瓜中选择一些瓜&#xff0c;可以选择将瓜劈成两半&#xff0c;使得最后的总重量恰好等于 m m m。我们的目标是求出至少需要劈多少个瓜。 首先&#xff0c;我们注意到每个瓜的重量最多为 1 0 9 10^9 109&#xff0c;而求和的重量 m m m 也最多为…

C++ 彻底搞懂指针(1)

当有人问起,什么是指针时,我会毫不犹豫地回答,指针变量存放的是地址!然后呢,好像也说不出什么了,今天就再来详细看一下指针吧。 本文提纲如下: • 指针变量 • 未初始化的指针 • NULL • void指针 • 指针的指针 首先要明白几点: • 每个字节都有…