本次作业需要模拟一个多线程实时电梯系统。
系统基于一个类似北京航空航天大学新主楼的大楼,大楼有 A,B,C,D,E五个座,每个楼座有对应的一台电梯,可以在楼座内 1-10 层之间运行。
系统从标准输入中输入请求信息,程序进行接收和处理,模拟电梯运行,将必要的运行信息通过输出接口进行输出。
具体而言,本次作业电梯系统具有的功能为:上下行,开关门,以及模拟乘客的进出。
电梯系统可以采用任意的调度策略,即在任意时刻,系统选择上下行动,是否在某层开关门,都可自定义,只要保证在电梯系统时间不超过系统时间上限的前提下将所有的乘客送至目的地即可。
电梯每上下运行一层、开关门的时间为固定值,仅在开关门窗口时间内允许乘客进出。
电梯系统默认初始在 A,B,C,D,E五个楼座的1层中各有一个电梯。
HW5基本思路本次作业是多线程第一次作业,要求实现五栋楼中各自的一个电梯,不涉及电梯间的信息交流。本次作业使用了简单的生产者消费者模式。笔者设计了三个线程类,一是输入线程,二是调度器线程,三是电梯线程。线程之间的通信依赖于线程安全的请求队列(核心成员为LinkedList<PersonRequest>)和候乘表(核心成员为HashMap<Integer, LinkedList<PersonRequest>>),二者实现了请求分派队列的接口。
UML图可以看出,似乎还是比较清晰的
时序图InputHandler作为生产者发送请求,Scheduler作为消费者接受请求,又作为生产者发送请求,电梯作为消费者接受请求
调度器设计与线程交互输入线程
与调度器线程共享一个请求队列,输入线程不断接受输入,如果没有输入就阻塞等待;如果有输入就将输入添加到请求队列中;输入结束就通知设置请求队列输入结束,并自身退出循环结束线程。
调度器线程
与输入线程共享一个请求队列,与电梯线程共享一个候乘表。调度器线程不断从请求队列中获取请求,如果获取到了请求,就根据请求的楼座将请求添加到对应的电梯的候乘表。当调度器线程与输入线程共享的请求队列被输入线程标记为输入结束,且请求队列为空时,将五个电梯线程的候乘表设置为工作结束,并退出循环,结束线程。
调度器只进行请求的接受的分配
电梯线程
与调度器线程共享一个候乘表,并拥有乘客队列。在电梯的run方法循环中
1.首先判断候乘表和乘客队列是否为空,若候乘表和乘客队列为空再判断是否候乘表工作结束,若候乘表工作结束则退出循环结束线程,否则电梯wait等待乘客。
2.接着根据策略类的判断设置电梯运行方向
3.再判断是否有乘客可以进入和是否有乘客需要离开,若有则开门并进行乘客离开和进入的操作(应当先离开再进入,否则可能出现拒载的情况)。
4.在电梯开门关门后再进行一次候乘表和乘客队列为空再判断是否候乘表工作结束的判断(可能出现乘客已经全部离开并且候乘表没有乘客的情况,若不判断,则电梯会到新的一层),即重复1、2步
5.根据策略类给出的方向进行电梯移动
调度策略调度策略封装在策略类中,电梯拥有策略类属性。
电梯根据候乘表的状态进行调度,而不是由调度器进行调度
本次作业调度策略采用look,具体如下:
1.若电梯中有乘客要到达的楼层在当前的方向上的前面,则保持当前方向不变
2.若1不成立,则若候乘表中有乘客出发的楼层在当前的方向上的前面,则保持当前方向不变
3.若1,2都不成立,则电梯原地等待
注意:策略类只是给出电梯前进的方向,电梯允许乘客进来仅当电梯没满员且乘客的方向与电梯前进的方向相同。如果不考虑电梯与乘客方向的匹配,比如电梯在上行,有下行的乘客进来了,会导致整体用时增加。
PS:其实我感觉look策略实现起来比ALS好像更简单且整体性能优于ALS,不知道为啥课程组要设置ALS为基准策略,是为了鼓励同学上网查资料?
电梯行为1.判断候乘表和乘客队列是否都为空
- 是的话判断是否候乘表工作结束
- 是的话电梯运行结束
- 否则等待
- 否则.根据策略类获得下一步的方向
3.乘客进出电梯
4.再次判断候乘表和乘客队列是否都为空(可能电梯出完了人导致乘客队列为空)
- 是的话判断是否候乘表工作结束
- 是的话电梯运行结束
- 否则等待
- 否则根据策略类获得下一步的方向
5.电梯根据方向到达下一层
第六次作业 题目说明本次作业在第一次作业的基础上新增了ABCDE五个楼座的横向电梯,并支持在运行中新增加竖直和横向电梯的请求,同时可以一栋楼或者一层楼有多部电梯
HW6基本思路第六次作业只是在第五次作业的基础上新增了横向电梯和新增竖直和横向电梯的请求,前者只需要对横向电梯新增加一个类,后者只需要在调度器中新增加对电梯请求的处理,二者处理起来比较简单。难点在于横向电梯的调度策略和多电梯的请求分配。前者我采用了横向look策略。
后者有两种处理方式,一种是课程组给的基准策略
在电梯的调度上,采用一种较为均衡的调度方式,例如 AA 座 77 层有5个乘客,3部电梯,那么第1个乘客分配给第1部电梯,第2个乘客分配给第2部电梯,第3个乘客分配给第3部电梯,第4个乘客分配给第1部电梯,第5个乘客分配给第2部电梯
另一种则是自由竞争
同一楼座或者楼层的电梯共享一个候乘表,当调度器把请求发送给某一层或者某一栋楼的候乘表后,所有电梯都能看到这个请求,然后根据自身的状态选择是否去竞争这个请求,虽然可能会出现陪跑的情况,但经过测试,性能还是比统一分配要高一点的。其实现实生活中也是这样,你坐电梯的时候把左右两个电梯都按了,哪个电梯先到你就进哪个。
其中自由竞争实现较为容易,于是我选择了自由竞争作为多电梯的调度策略。
UML图竖直电梯和横向电梯拥有各自的候乘表类和策略类,其实可以让横向候乘表类和竖直候乘表类实现候乘表类接口,横向策略类和竖直策略类实现策略类接口,可是当时没有时间,就没有实现