触发设备离线

业务场景

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

环形队列
 

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.hqwc.cn/news/206649.html

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

相关文章

【MySQL】多表查询、子查询、自连接、合并查询详解,包含大量示例,包你会。

复合查询 前言正式开始一些开胃菜多表查询自连接子查询单行子查询多行子查询in关键字all关键字any关键字多列子查询在from中使用子查询 合并查询union 和 union all 前言 我前面博客讲的所有的查询都是在单表中进行的&#xff0c;从这里开始就要专门针对查询这个话题进行进一步…

HTML5+CSS3+JS小实例:霁青+翠蓝的Tabbar动画特效

实例:霁青+翠蓝的Tabbar动画特效 技术栈:HTML+CSS+JS 字体图标库:Font Awesome 效果: 源码: 【HTML】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta nam…

虚拟摇杆OnJoystickMove未被调用,角色不移动

更改interaction type 为 event notification

2023-11-21 LeetCode每日一题(美化数组的最少删除数)

2023-11-21每日一题 一、题目编号 2216. 美化数组的最少删除数二、题目链接 点击跳转到题目位置 三、题目描述 给你一个下标从 0 开始的整数数组 nums &#xff0c;如果满足下述条件&#xff0c;则认为数组 nums 是一个 美丽数组 &#xff1a; nums.length 为偶数对所有满…

12、人工智能、机器学习、深度学习的关系

很多年前听一个机器学习的公开课,在Q&A环节,一个同学问了老师一个问题“机器学习和深度学习是什么关系”? 老师先没回答,而是反问了在场的同学,结果问了2-3个,没有人可以回答的很到位,我当时也是初学一脸懵,会场准备的小礼品也没有拿到。 后来老师解释“机器学习和…

基于单片机电梯液晶显示防超重,防气体报警、防夹报警控制系统及源程序

一、系统方案 1、本设计采用51单片机作为主控器。 2、液晶显示楼层。 3、防超重&#xff0c;防气体报警、防夹报警。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 /lcd1602初始化设置*/ void init_1602() //lcd1602初始化设置 { write_co…

关于ElectronVue3中集成讯飞星火AI

前言&#xff1a;我的最终目的是为了在QQ上集成一个AI机器人&#xff0c;因此在这里先实现一个简单的集成 先上效果图 总体还是很简单的&#xff0c;我在调用websock获取回复内容的基础上另外集成了一个事件总线&#xff0c;让我们在调用获取消息的时候能够更加方便快捷 工具代…

表格制作软件排行榜,热门做表格的软件推荐

在数字化时代&#xff0c;表格不仅仅是企业管理和数据整理的重要工具&#xff0c;更是学术研究、项目规划以及日常生活中必不可少的一部分。为了更高效地进行表格制作&#xff0c;选择一款优秀的表格制作软件是至关重要的。在众多的软件中&#xff0c;我们特别推荐一款备受好评…

“KeyarchOS:国产Linux新星的崛起与创新之路“

简介 KeyarchOS是一款由浪潮信息自主研发的服务器操作系统。它因为几个特点而受到我的青睐和一些用户的关注。 首先&#xff0c;KeyarchOS注重安全性和稳定性。它有一些防护和隔离功能&#xff0c;来帮助系统稳定运行&#xff0c;而且是中文语言更接地气。 其次&#xff0c;Ke…

银行数字化转型导师坚鹏:BLM银行数字化转型战略培训圆满结束

在数字化转型背景下&#xff0c;中国金融出版社金融文化研训院为了落实监管政策《关于银行业保险业数字化转型的指导意见》&#xff0c;充分认识到学习银行银行数字化转型战略的价值和重要性&#xff0c;特别举办《2023年金融机构数字化转型及数字化风控与运营管理研讨班》。为…

STM32F103C8T6第5天:独立看门狗、窗口看门狗、dma实验

1. 独立看门狗IWDG介绍&#xff08;341.45&#xff09; 什么是看门狗&#xff1f; 在由单片机构成的微型计算机系统中&#xff0c;由于单片机的工作常常会受到来自外界电磁场的干扰&#xff0c;造成程序的跑飞&#xff0c;而陷入死循环&#xff0c;程序的正常运行被打断&#…

python实现鼠标实时坐标监测

python实现鼠标实时坐标监测 一、说明 使用了以下技术和库&#xff1a; tkinter&#xff1a;用于创建GUI界面。pyperclip&#xff1a;用于复制文本到剪贴板。pynput.mouse&#xff1a;用于监听鼠标事件&#xff0c;包括移动和点击。threading&#xff1a;用于创建多线程&…