主机状态一直显示有问题,去向动态连接库请求数据时,除了第一台主机访问成功外,之后的每一台主机返回的结果都是9(HOST_NOT_FOUND)
。java
研究了好久也没研究明白,最后求助潘老师。安全
潘老师指出是指针有问题,主机的指针是咱们构造出来的,虽然该指针指向对象的name
和context
与动态连接库服务那边的都同样,可是他那里多是按地址处理的,不是同一个地址,就报主机找不到了。服务器
通过测试,确实是这样。并发
不能直接构造指针,须要使用同步计算机数据时返回的指针进行操做。测试
因此,获取计算机状态,操做计算机都须要从新同步一下计算机,将指针同步过来。this
假设用户操做很频繁的话,对动态连接库的压力就很大。指不定啥时候就炸了。spa
虽然我想到了这点,但也没想到好的解决方案。线程
潘老师最终的设计方案很是好,采用定时任务,当有计算机的操做时,不实时进行操做,而是先存起来,每隔一段时间统一进行操做,从而减轻服务器压力。debug
对主机进行关机或重启时,不当即执行,而是将其添加到一个要执行的任务列表中,当定时任务触发后,再统一执行。设计
定时任务很简单,以前在计量中写过一个天天晚上定时统计数据的定时任务,此次写这个没什么难度,都不须要看文档了。
注释很详尽,相信聪明的你彻底能够理解。
这里的存储计算机状态设置了一个主机名到计算机状态映射的HashMap
,这里没有用ConcurrentHashMap
,由于只有定时任务一个线程进行put
,其余接口调用该Map
只负责查询,不会出现冲突。
@Async @Scheduled(fixedRate = 10000) // 每隔10s执行 public void hostHandle() { logger.info("--- 开始执行定时任务 ---"); logger.debug("获取关机重启的订阅者"); Set<String> shutdownSubscribers = this.cloneStringSetAndClear(hostService.getShutdownSubscribers()); Set<String> rebootSubscribers = this.cloneStringSetAndClear(hostService.getRebootSubscribers()); logger.debug("获取主机结构体指针Map"); List<HostStruct.ByReference> byReferenceList = baseService.getHostStructReferenceList(); Map<String, HostStruct.ByReference> byReferenceMap = baseService.getHostStructReferenceMap(byReferenceList); if (!shutdownSubscribers.isEmpty()) { logger.info("存在关机订阅,执行关机操做"); for (String name : shutdownSubscribers) { logger.debug("获取结构体指针并关机"); HostStruct.ByReference byReference = byReferenceMap.get(name); baseService.shutdown(byReference); } } if (!rebootSubscribers.isEmpty()) { logger.info("存在重启订阅,执行重启操做"); for (String name : rebootSubscribers) { logger.debug("获取结构体指针并重启"); HostStruct.ByReference byReference = byReferenceMap.get(name); baseService.reboot(byReference); } } logger.debug("查询主机列表"); for (HostStruct.ByReference byReference : byReferenceList) { logger.debug("查询主机指针,同时获取主机信息"); Integer status = baseService.getHostStatus(byReference); logger.debug("添加到Map中"); hostService.getHostStatusMap().put(Native.toString(byReference.name), status); } logger.info("--- 定时任务执行完毕 ---"); } /** * 克隆字符串集合并清空原集合 * @param primarySet 原集合 * @return 克隆的字符串集合 */ private Set<String> cloneStringSetAndClear(Set<String> primarySet) { logger.debug("新建集合"); Set<String> set = new HashSet<>(primarySet); logger.debug("清空原集合"); primarySet.clear(); logger.debug("返回"); return set; }
目前是用Set
存储要操做的主机,可是通过查询,HashSet
、LinkedHashSet
、TreeSet
都是线程不安全的。
这里就怕执行定时任务的时候,忽然来了一个关机的指令,两个线程同时访问Set
,定时任务要克隆一个Set
而后把这个清空,关机须要在Set
中添加元素,两个线程若是交替执行,结果就很难说了。
去concurrent
包下找,也没找到合适的。看了看,有第三方库实现的线程安全的Set
,之后引入进来。
这里不知道是否是我用的有问题,是并发场景下不推荐用Set
吗?为何concurrent
包下没有相关的实现类?
感叹一句:C++
仍是难啊!
C++
老师对个人评价是字写得还不错,哈哈哈。佩服C++
工程师!