触发设备离线

业务场景

业务开发过程中,我们经常会需要判断远程终端是否在线,当终端离线的时候我们需要发送消息告知相应的系统,

环形队列
 

1.创建一个index从0到30的环形队列(本质是个数组)
2.环上每一个slot是一个Set,任务集合
3.同时还有一个Map<uid, index>,记录uid落在环上的哪个slot里
4.启动一个timer,每隔1s,在上述环形队列中移动一格,0->1->2->3…->29->30->0…
5.有一个Current Index指针来标识刚检测过的slot
6.接收到设备心跳后将寻找到原来uid的位置然后移动到当前指针的后一位,并删除原来slot里的uid
7.这样就可以快速获取超时的设备uid

环形队列实现

package com.zngx.admin.circle;import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** @Author : zhiying* @Date : 2022-11-22 15:17* @Desc : 环形队列 - 设备离线判定* 1、预设一个长度为10000的数组(按实际业务定义长度)* 2、每个数组存放一个Set集合* 3、维护一个游标cur,从0到9999递增,到达9999时,重置为0(启动一个线程执行)* 4、维护一个map,记录所有设备ID存放的数组位置,方便查找* 5、监听到设备心跳时,先将原来的数据从指定位置的集合中删除,通过计算当前游标位置和keepAlive寻找合适的位置将设备ID放入* 6、当游标指向某个位置a时,a位置的集合中的所有设备全部判定为离线,并清空该位置的集合**/public class CircleQueue<T> {//线程安全锁Lock lock = new ReentrantLock();//初始环形队列大小private int capacity = 10000;//当前环形队列所在节点private volatile int currentIndex = 0;//数据所在节点private Map<T,Integer> dataIndex = new HashMap<>();//环形队列private Set<T>[] array;public CircleQueue(){array = new HashSet[capacity];}public CircleQueue(int capacity){this.capacity = capacity;array = new HashSet[capacity];}/*** 向环形队列中添加元素* @param t* @param offset 偏移量,基于游标*/public void add(T t, int offset){int index = currentIndex + offset;if(index >= capacity){index = index - capacity;}try {lock.lock();//判断数据是否存在if(dataIndex.containsKey(t)){Set<T> old  =  array[dataIndex.get(t)];old.remove(t);}//获取当前节点的队列Set<T> set = array[index];if(null == set){set = new HashSet<>();array[index] = set;}set.add(t);//更新新的节点位置dataIndex.put(t,index);}catch (Exception e){e.printStackTrace();}finally {lock.unlock();}}/*** 下移一格,到9999重新置为0*/public void next(){int cur = currentIndex + 1;if(cur >= capacity){cur = cur - capacity;}currentIndex = cur;System.out.println("当前游标位置:" + currentIndex);}/*** 获取当前游标指向的元素集合* @return*/public Set<T> getAndDeleteData(){Set<T> set = null;try {lock.lock();set = array[currentIndex];return set;}finally {// 将集合中所有的元素移除array[currentIndex] = new HashSet<>();if(set != null && set.size()>0){set.forEach(t -> {dataIndex.remove(t);});}lock.unlock();}}public int getIndex(T t){if(dataIndex.containsKey(t)){return dataIndex.get(t);}return -1;}
}

测试代码 

    @Testpublic void circleTest(){CircleQueue<String> circleQueue = new CircleQueue<>();for (int i=0;i<1000;i++){String uuid = String.valueOf(i+1);int offset = (int) Math.round(Math.random()*10);circleQueue.add(uuid, offset);}checkTimeout(circleQueue);insertDataRandom(circleQueue);try {Thread.sleep(600000);}catch (Exception e){e.printStackTrace();}}private void checkTimeout(CircleQueue<String> circleQueue){service.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {Set<String> set = circleQueue.getAndDeleteData();if(set == null || set.isEmpty()) {System.out.println("本次没有设备离线");}else{System.out.println("这些设备离线啦:" + Joiner.on(",").join(set));}circleQueue.next();}},2,1, TimeUnit.SECONDS);}private void insertDataRandom(CircleQueue<String> circleQueue){service.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {String deviceId = String.valueOf(Math.round(Math.random()*100000));int offset = (int) Math.round(Math.random()*10);circleQueue.add(deviceId, offset);System.out.println("插入设备["+deviceId+"], " + offset + "秒后离线");}},3,3, TimeUnit.SECONDS);}

 测试结果

148aed53-a083-40a6-82d3-ede14e5e39c9初始时间1585571543739
当前位置:0数据大小:0
当前位置:1数据大小:0
当前位置:2数据大小:0
当前位置:3数据大小:0
当前位置:4数据大小:0
148aed53-a083-40a6-82d3-ede14e5e39c9不移动位置29
当前位置:5数据大小:0
当前位置:6数据大小:0
当前位置:7数据大小:0
当前位置:8数据大小:0
当前位置:9数据大小:0
当前位置:10数据大小:0
当前位置:11数据大小:0
当前位置:12数据大小:0
当前位置:13数据大小:0
当前位置:14数据大小:0
148aed53-a083-40a6-82d3-ede14e5e39c9不移动位置29
当前位置:15数据大小:0
当前位置:16数据大小:0
当前位置:17数据大小:0
当前位置:18数据大小:0
当前位置:19数据大小:0
当前位置:20数据大小:0
当前位置:21数据大小:0
当前位置:22数据大小:0
当前位置:23数据大小:0
当前位置:24数据大小:0
148aed53-a083-40a6-82d3-ede14e5e39c9不移动位置29
当前位置:25数据大小:0
当前位置:26数据大小:0
当前位置:27数据大小:0
当前位置:28数据大小:0
148aed53-a083-40a6-82d3-ede14e5e39c9过期
超时时间30005

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

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

相关文章

python 执行系统命令

subprocess 模块和 os.system 或 os.popen 等函数相比&#xff0c;功能更为强大和灵活&#xff0c;是 Python 官方推荐的执行系统命令的方法。主要的优势包括&#xff1a; 更强的错误处理&#xff1a;subprocess 模块可以更精细地控制错误输出和错误代码&#xff0c;而 os.syst…

自定义springboot的生命周期函数在项目启动完成后去取配置文件中的值

主要是实现smartLifecycle类 package com.ruoyi.workflow.util;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springfr…

MYSQL索引使用注意事项

索引使用注意事项&#xff1a; 1.索引列运算 不要在索引列上进行运算操作&#xff0c;否则索引将失效&#xff1b; 2.字符串不加引号 字符串类型使用时&#xff0c;不加引号&#xff0c;否则索引将失效&#xff1b; 3.模糊查询 如果仅仅是尾部模糊匹配&#xff0c;索引将不会失…

防火墙暴露端口

如果你想开通防火墙上的端口&#xff0c;具体的操作方式可能会取决于你所使用的操作系统。以下是一些常见操作系统的步骤&#xff1a; 1. Linux&#xff08;例如&#xff0c;Ubuntu 或 CentOS&#xff09;: 使用 ufw&#xff08;适用于 Ubuntu&#xff09;&#xff1a; # 开…

RK平台查看板子上的dts信息

简介 dts文件描述了硬件每个模块的信息&#xff0c;我们嵌入式软件的调试很多时候都是在改dts文件&#xff0c;有时候我们不确定板子上的固件是否已经更新了我们的修改&#xff0c;这时候我们可以直接读取板子上的dts信息&#xff0c;下面来演示一下。 进入uboot命令行模式 …

关于软raid的实现及常见问题

RAID概念 磁盘阵列&#xff08;Redundant Arrays of Independent Disks&#xff0c;RAID&#xff09;&#xff0c;有“独立磁盘构成的具有冗余能力的阵列”之意。 磁盘阵列是由很多价格较便宜的磁盘&#xff0c;以硬件&#xff08;RAID卡&#xff09;或软件&#xff08;MDADM&…

关于用css设置input输入框hover的时候的样式以及当input为disabled的时候,不要让hover样式生效

效果如果&#xff1a; 编辑状态下的时候&#xff1a; 只读状态下的时候&#xff1a; 代码如图&#xff1a; <input type"text" name"dataForm.exportCode" id"exportCodeItem" required :disabled"editDisabled" />input:not(…

【前端学java】语法练习-工具类的封装(13)

往期回顾&#xff1a; 【前端学java】JAVA开发的依赖安装与环境配置 &#xff08;0&#xff09;【前端学 java】java的基础语法&#xff08;1&#xff09;【前端学java】JAVA中的packge与import&#xff08;2&#xff09;【前端学java】面向对象编程基础-类的使用 &#xff08…

java.net.UnknownHostException: eureka

java.net.UnknownHostException: eureka 哦。HOST漏了 #linux /etc/hosts #windows C:\Windows\System32\drivers\etc\hosts 127.0.0.1 eureka7000 127.0.0.1 eureka7001 127.0.0.1 eureka7002

maven打包可执行jar含依赖lib

修改pom.xml <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><!-- jdk8可用&#xff0c;其他jdk版本可能需改插件版本 --><version>2.3.7.RE…

sql调优

慢查询 SQL 治理方案 一、SQL 性能下降的原因 在对 SQL 进行分析之前&#xff0c;需要明确可能导致 SQL 执行性能下降的原因进行分析&#xff0c;执行性能下降可以体现在很多方面&#xff1a; 查询语句写的烂索引没加好表数据过大数据库连接数不够查询的数据量过大被其他慢s…

MyBatisPlus代码生成

基础依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.…

visual studio 如何建立 C 语言项目

安装这个 模块。 新建 空项目 创建完成 写demo 点击运行&#xff1a;

【1day】泛微e-office OA系统user_page接口未授权访问漏洞学习

注:该文章来自作者日常学习笔记,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与作者无关。 目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现

Web项目从Tomcat迁移到TongWeb

注意事项 1. 使用JNDI方式获取数据源&#xff1a; ①在TongWeb创建JDBC连接池; ②修改Web项目数据源配置. #spring.datasource.urljdbc:mysql://127.0.0.1:3306/demo #spring.datasource.usernametest #spring.datasource.passwordspring.datasource.jndi-namedemo2. 修…

Spring cloud - Hystrix源码

其实只是Hystrix初始化部分&#xff0c;我们从源码的角度分析一下EnableCircuitBreaker以及HystrixCommand注解的初始化过程。 从EnableCircuitBreaker入手 我们是通过在启动类添加EnableCircuitBreaker注解启用Hystrix的&#xff0c;所以&#xff0c;源码解析也要从这个注解…

最新PHP熊猫头图片表情斗图生成源码

这是一款能生成熊猫头表情斗图的自适应系统源码&#xff0c;无论是在电脑还是手机上都可以正常使用&#xff01;这个源码集成了搜狗搜索图片接口&#xff0c;可以轻松地一键搜索数百万张图片&#xff0c;并且还包含了表情制作等功能模块。对于一些新站来说&#xff0c;这是一个…

Cloud微服务

当我们谈论“云微服务”时&#xff0c;通常是指基于云计算和微服务架构的应用程序开发和部署模型。以下是关于云微服务的一些详细信息&#xff1a; 微服务架构&#xff1a; 微服务架构是一种软件设计和开发模式&#xff0c;将应用程序划分为一组小型、独立的服务单元。每个服…

c++ LRU(最近最少使用)缓存机制

// LRU(最近最少使用)缓存机制 #ifndef _ZD_LRU_CACHE_H_ #define _ZD_LRU_CACHE_H_#include <unordered_map> #include <list> #include <mutex>class ZDLRUCahce { public:ZDLRUCahce(int capacity): m_capacity(capacity){}~ZDLRUCahce(){}// 1.key不存在…