【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可以提供一个简单、可控且高效的方式来管理流程中的定时任务,同时确保流程的稳定性和可预测性。

java 复制代码
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);

        // 立即执行柔性调温策略1
        scheduler.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);

        // 五分钟之后执行applyFlexibleTempStrategy2
        scheduler.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:false
        redissonClient.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:false
        redissonClient.getBucket(EMERGENCY_STOPPED_KEY + planId).set(EMERGENCY_STOPPED);
    }

    /**
     * 下发遥调指令
     */
    private boolean packageCommandTempIssuance() {
        // 下发遥调指令,示意代码
        return true;
    }

    /**
     * 下发召测命令
     *
     * @return 不满足数量
     */
    private Integer packageCallForTest() {
        // 下召测命令,拿内机数据,示意代码
        return 0;
    }
}
相关推荐
yhole2 分钟前
springboot 修复 Spring Framework 特定条件下目录遍历漏洞(CVE-2024-38819)
spring boot·后端·spring
大傻^3 分钟前
Spring AI 2.0 MCP 协议实战:Model Context Protocol SDK 与多服务器编排
服务器·人工智能·spring
BingoGo7 分钟前
Laravel 13 正式发布 使用 Laravel AI 无缝平滑升级
后端·php
愣头不青11 分钟前
560.和为k的子数组
java·数据结构
共享家952718 分钟前
Java入门(String类)
java·开发语言
l软件定制开发工作室23 分钟前
Spring开发系列教程(34)——打包Spring Boot应用
java·spring boot·后端·spring·springboot
0xDevNull25 分钟前
Spring Boot 循环依赖解决方案完全指南
java·开发语言·spring
爱丽_25 分钟前
GC 怎么判定“该回收谁”:GC Roots、可达性分析、四种引用与回收算法
java·jvm·算法
bbq粉刷匠26 分钟前
Java--多线程--单例模式
java·开发语言·单例模式
随风,奔跑27 分钟前
Spring MVC
java·后端·spring