SpringBoot多线程——排队叫号实验模拟(二)

SpringBoot多线程——排队叫号模拟实验(二)

1. 前言

本文是前面一篇文章的续集。与之前的思路略有出入。
先来做个回顾,体检中心需要模拟客户多次排队叫号的流程,现在提出如下图所示的解决方案。Thread A是异步单线程,主要负责从客户信息List中取出一个人来,按一定间隔时间放入缓冲池里面;Thread B是异步单线程,主要负责从缓冲池中提取优先级最大的客户,通过计算判断出一个局部最优解的科室,将客户分配至该科室的队列等候体检(也就是分配到redis队列中);ThreadC是异步多线程,但我希望每个线程只做自己的事情,即每个线程模拟一个科室,按传入的参数从代表自己的科室等待队列里面捞人,然后睡眠一段时间作为模拟检查时间,最后再次进行计算,将客户分配到计算结果科室的队列。直到最后所有客户全部完成体检为止。

SpringBoot多线程——排队叫号实验模拟(二)

2. Thread C的逻辑代码

    /**
     * 通过此方法开启多个线程模拟科室叫号完成,并再次自动分配
     * @param roomCode
     * @param stayTime
     */
    @Async("RoomTaskExecutor")
    @Override
    public void checkRoomScheduleTemplate(String roomCode, long stayTime) {
        log.info("启动时间: {}", new Date());
        QueryWrapper qw = new QueryWrapper();
        qw.eq("room_code", roomCode);
        RoomInfo currentRoom = roomInfoService.getOne(qw);
        while (true) {
            if (queueUtil.getQueueLength(roomCode) != 0L) {
                // 有人就取,没人就一直监听
                // 取出队首
                PatientVo vo = queueUtil.headLeaveQueue(roomCode);
                // 更新叫号时间
                checkRecordDBUpdateCallingTime(new Date(), vo.getPatientId(), currentRoom.getRoomId());
                // 存入检查科室
                roomUtil.set2Room(roomCode, vo);
                // 开始检查逗留
                try {
                    log.info("{}时刻, {}在{}开始检查", new Date(), vo.getPatientName(), currentRoom.getRoomName());
                    Thread.sleep(stayTime);
                    log.info("{}时刻,{}在{}完成检查.", new Date(), vo.getPatientName(), currentRoom.getRoomName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 完成逗留,开始完成体检业务
                // 保存完成时间
                checkRecordDBUpdateFinishedTime(new Date(), vo.getPatientId(), currentRoom.getRoomId());
                // 计算下一科室
                RoomInfo nextRoom = algorithmService.computeNextRoom(patientInfoService.getById(vo.getPatientId()));
                if (nextRoom == null) {
                    String nextMsg = vo.getQueueNum() + vo.getPatientName() + " 下一科室: 采样室留样后前台交表";
                    // 写入redis
                    stringRedisTemplate.opsForHash().put("nextCheck", roomCode, nextMsg);
                    // 添加到完成表里面,并结束本轮循环
                    log.info("{}时刻, {}完成了体检!", new Date(), vo.getPatientName());
                    continue;
                    // TODO: 实验结束
                }
                // 前端下一检查消息创建
                String nextMsg = vo.getQueueNum() + vo.getPatientName() + " 下一科室: " + nextRoom.getRoomName();
                // 写入redis
                stringRedisTemplate.opsForHash().put("nextCheck", roomCode, nextMsg);
                queueUtil.addPatient2Queue(nextRoom.getRoomCode(), vo);
                // 科室正在检查可以更换为空了
                roomUtil.set2Room(roomCode, new PatientVo());
                // 添加入队记录
                CheckRecord record = new CheckRecord(null, vo.getPatientId(), nextRoom.getRoomTypeId(), nextRoom.getRoomId(), new Date(), null, null, Boolean.FALSE);
                checkRecordDBSave(record);
            }
        }
    }

3. 总结与反思

SpringBoot底层怎么做到的多线程还是没有探究清楚,目前就是瞎猫碰上个死老鼠一样试出来的效果,不保证后续稳定安全,而且while死循环一直没被打破是个问题,而且在多线程中使用Thread.sleep并不好,所以后面有新方案改进再拿出来批评修正。最后说说部分博客文章,线程池配置的注释写错了导致我以为有了新发现,真的应该多看一手材料的,但信息检索能力太差了,基础也太差了,暂时先把项目做完,然后逐步提升基础吧。

参考文章

SpringBoot @Async 注解使用总结,配置系统线程池

Original: https://www.cnblogs.com/ceeSomething8/p/15956019.html
Author: cee_nil
Title: SpringBoot多线程——排队叫号实验模拟(二)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/621578/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球