触发设备离线

业务场景

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

环形队列
 

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,一经查实,立即删除!

相关文章

MYSQL索引使用注意事项

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

关于软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…

visual studio 如何建立 C 语言项目

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

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;这是一个…

JavaScript的过滤大师:深度解析Filter用法

JavaScript的过滤大师&#xff1a;深度解析Filter用法 前言基础篇filter的基本用法语法示例 自定义过滤函数数组对象的过滤复杂条件的筛选常见应用场景性能优化注意性能的建议在大规模数据集下的优化方法 案例分析实际案例&#xff1a;用户筛选使用 filter 方法解决问题代码优化…

产品工程师工作的职责十篇(合集)

一、岗位职责的作用意义 1.可以最大限度地实现劳动用工的科学配置; 2.有效地防止因职务重叠而发生的工作扯皮现象; 3.提高内部竞争活力&#xff0c;更好地发现和使用人才; 4.组织考核的依据; 5.提高工作效率和工作质量; 6.规范操作行为; 7.减少违章行为和违章事故的发生…

好视通视频会议系统(fastmeeting) toDownload.do接口存在任意文件读取漏洞复现 [附POC]

文章目录 好视通视频会议系统(fastmeeting) toDownload.do接口存在任意文件读取漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 好视通视频会议系统(fastmeeting) toDownload.do接口存在任意文件…

超详细!新手必看!STM32-通用定时器简介与知识点概括

一、通用定时器的功能 在基本定时器功能的基础上新增功能&#xff1a; 通用定时器有4个独立通道&#xff0c;且每个通道都可以用于下面功能。 &#xff08;1&#xff09;输入捕获&#xff1a;测量输入信号的周期和占空比等。 &#xff08;2&#xff09;输出比较&#xff1a;产…

Gradle常用命令与参数依赖管理和版本决议

一、Gradle 常用命令与参数 本课程全程基于 Gradle8.0 环境 1、Gradle 命令 介绍 gradle 命令之前我们先来了解下 gradle 命令怎么在项目中执行。 1.1、gradlew gradlew 即 Gradle Wrapper&#xff0c;在学习小组的第一课时已经介绍过了这里就不多赘述。提一下执行命令&am…

.Net6使用WebSocket与前端进行通信

1. 创建类WebSocketTest&#xff1a; using System.Net.WebSockets; using System.Text;namespace WebSocket.Demo {public class WebSocketTest{//当前请求实例System.Net.WebSockets.WebSocket socket null;public async Task DoWork(HttpContext ctx){socket await ctx.We…

为UE和Unity开发者准备的Godot指南

为UE和Unity开发者准备的Godot指南 ——两位大哥打架&#xff0c;请带上我 这两天游戏行业又开始热闹了&#xff0c;昨天两条信息直接刷爆朋友圈&#xff0c;最大的两家游戏引擎公司怼起来了。 《为Unity开发者准备的虚幻引擎指南》&#xff1a; 为Unity开发者准备的虚幻引擎指…

sso 四种授权模式

单点登录 单点登录&#xff0c;英文是 Single Sign On&#xff08;缩写为 SSO&#xff09;。即多个站点共用一台认证授权服务器&#xff0c;用户在站点登录后&#xff0c;可以免登录访问其他所有站点。而且&#xff0c;各站点间可以通过该登录状态直接交互。例如&#xff1a; …