电梯调度设计分析

电梯调度设计分析

一、设计分析

1. 单部多线程电梯傻瓜调度(FAFS)

  • 这次作业需要模拟一个多线程实时电梯系统,需要实现人员的运输与进出电梯以及电梯的开关门。由于这次作业中并没有性能分的要求,所以只需要完成最基础的运输操作就可以在这次作业中取得满分,换句话说第五次作业几乎是人人满分。

  • 我的程序架构中,使用了两个线程,输入线程和电梯线程,同时还有一个请求队列的类,用于管理新来的请求和把请求传递给电梯,利用 FAFS (先来先服务)的原则,可以很好的实现电梯的架构

  • 下面是我这次作业程序的 UML 类图:

  • 从类图中可以发现,ElevatorInputQueue 是两个继承了 run() 方法的线程类,其他的类都是辅助这两个类进行的构建。

  • Method 复杂度分析:

  • Class 复杂度分析

  • 这两者的复杂度都算控制得比较正常。

2. 单部多线程可捎带调度电梯(ALS)

  • 第二次电梯作业,需求相较于第一次增加了时间的要求,需要我们在运行过程中增加“可捎带”的能力,当然,作业需求并没有限制我们捎带的方式,而是通过运行总时间的限制来确保我们对电梯调度进行了优化,我认为这是非常好的限制方式,因为这样我们可以大胆发挥,在时间允许的情况下可以使用任何的优化策略。

  • 第二次的代码架构,我在第一次作业的基础上只修改了需求队列的模块和电梯线程的模块,因为输入模块和第一次并无不同。

  • 优化的策略我采用了 SSTF (寻找最短时间优先)的策略,如果电梯中没有人,我将会从需求队列中取出运行时间最少的人作为首选,同时在去接他的路途中检查是否可以捎带;如果电梯中有人,我会选取所需时间最少的那个人作为优先服务的人,然后在路途中寻找捎带,一旦电梯中的人员发生变化,我会重复上述的两种查找主请求的方式,知道请求队列为空。

  • 因为这次作业设计的线程交互比上次更复杂了,所以我在请求队列的“查找”、“输入”、“输出” 的方法前加上了 synchronized 修饰词来保证线程安全。

  • 下面是第二次电梯作业的 UML 图:

  • 可以看出来我和第一次作业采用了一样的 架构,只是在 RequestQueueElevator 这两个类进行了修改。

  • 下面是代码复杂度分析:

  • 电梯类的使用还是比第一次作业有所增加的。

3. 多部多线程智能电梯调度(SS)

  • 第三次电梯作业据说是 OO 作业难度的顶峰,但是仔细分析需求后发现其实也没有难上天。这次我们需要调度三部电梯,每部电梯都有最大载客量的限制,并且最大载客量都不同,并且每部电梯可以开关门的楼层都不相同,这一限制大大增加了调度的难度。

  • 下面来看看我的优化策略,通过观察可以发现,任何一个请求都是可以由至多两个电梯完成的,所以请求可以分为两类:一部电梯可以完成的、需要两部电梯协作完成的。对于第一种请求,我直接派发给相应的电梯,对于第二种,我会排除四种特殊情况后派发给相应的两部电梯。派发的时候,程序会尽量派发给多的电梯,当某一部电梯将一个请求接走是,会移除其他请求队列中相同的请求,这样可以大大降低电梯满载时的调度效率。

  • 代码实现的过程中,由于这次的线程交互比起前两次作业有了大量的增加,所以我把三个电梯的请求队列写在一个类中,通过 synchronized 加锁的方法实现线程安全。

  • 下面是第三次作业的 UML 图:

  • 设计了三个电梯的线程分别运行。

  • 下面是代码复杂度分析:

  • 每个电梯的调度以及移除相同请求的类是用的特别多(都是为了线程安全考虑啊)。

二、Bug 分析

  • 由于前两次作业线程交互非常简单,所以我既没有发现自己程序的 Bug ,在互测中也没有发现别人程序的 Bug ,所以这个板块我直入正题,讲讲第三次作业的 Bug 。
  • 第三次作业中,涉及到的线程交互非常多,从输入、输出、到删除元素等等,任何一环出现问题都可能导致整个线程的崩塌,所以为了更好的并且大量地发现自己程序中的 Bug,我和另外四位同学编写了一个自动评测机。
  • 这个评测机可以实现自动生成随机输入数据,自动完成 Java 程序的运行并得到输出,验证输出结果的正确性,最后把错误数据储存下来。
  • 通过评测机的运行,我找到了第三次作业程序中的一个小 Bug ,和电梯的最大载客量有关。在电梯为空的时候,程序会寻找时间最短的人作为主请求去接他,但是路途中会不断捎带,虽然我在捎带时作了人数需小于最大人数的限制,但是最后还要去接那个主请求的人,最终会导致电梯超载,程序错误。

三、收获与总结

  • 通过这三次电梯的作业,今后坐电梯时就会忍不住思考这个电梯采用的是什么调度方式,我掌握了多线程这种有趣的编程模式,以往我写过的所有程序,都是单线程模式的运行,从来不会出现需要考虑两个对象间的交互会产生冲突的情况,多线程编程则需要考虑到。
  • 而多线程编程的关键则在于线程一定要保证安全,无论是通过 synchronized 加锁,还是 wait() notify() ,甚至是信号量的变化来控制线程,都必须保证线程的同步。
  • 另外值得欣喜的是,经过这三次电梯程序的训练,我已经基本掌握了面向对象编程的思想,每次写程序也都考虑到通过类来建立不同的对象实例,也不会出现之前几次作业写完代码后用 CheckStyle 检查代码风格一大堆错误的情况,这都说明着我写面向对象代码的能力在向好的方向发展。
posted @ 2019-04-23 20:57  Delicate1989  阅读(1056)  评论(0)    收藏  举报