【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;
    }
}
相关推荐
乌啼霜满天2491 分钟前
JDBC编程---Java
java·开发语言·sql
微信-since811929 分钟前
[ruby on rails] 安装docker
后端·docker·ruby on rails
色空大师14 分钟前
23种设计模式
java·开发语言·设计模式
闲人一枚(学习中)14 分钟前
设计模式-创建型-建造者模式
java·设计模式·建造者模式
2202_7544215432 分钟前
生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件
java·linux·开发语言
蓝染-惣右介34 分钟前
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
java·数据库·tomcat·mybatis
小林想被监督学习35 分钟前
idea怎么打开两个窗口,运行两个项目
java·ide·intellij-idea
HoneyMoose37 分钟前
IDEA 2024.3 版本更新主要功能介绍
java·ide·intellij-idea
我只会发热39 分钟前
Java SE 与 Java EE:基础与进阶的探索之旅
java·开发语言·java-ee
是老余40 分钟前
本地可运行,jar包运行错误【解决实例】:通过IDEA的maven package打包多模块项目
java·maven·intellij-idea·jar