OO_电梯专题_小结
概述:
这三次作业,我采取的类的构造方法大体一致:构造乘客Person对象、等待队列Waiting队列、电梯线程Elevator、读入线程Input以及Main类。
共性上仍有几大缺点:对线程的同步性控制不是很好,后两次可以优化的作业中,我都没有进行什么优化,下面我将对三次作业逐一分析
第一次:纯傻瓜电梯调度
一、分析自己程序结构
如图所示是我构建的类与之间的结构:
Person类基本是PersonRequest,但增加了结束标志
Input线程和Elevator线程共享一个类型为Waiting的对象(该对象中存储的是还未上电梯的Person),
Elevator从等待队列中取出一个等待的人,并根据该人需求移动电梯和开关门;若等待队列为空则wait(),若输入的Person的finish标志为真,则结束该线程
Input读入到数据,只要读到数据就会notifyall()一下,从而如果Elevator在等待则可唤醒;如果得到的数据是null,则构建一个finish标志为真的Person,传入队列,并结束该线程。
通过以上的结构,可以完成接人,送人及结束电梯的工作
二、自己的bug
由于这次是傻瓜调度,也不涉及时间限制,故我没被发现bug
三、发现别人的bug
这次也没发现别人的bug
第二次作业、有捎带的电梯调度
一、 分析自己的程序
可以看到,这次我的Main、Input、Person类都没有进行太大改变,最大的改变是Elevator线程,Waiting中也添加了对应的方法,主要是为了解决可捎带问题,下面我将进行具体说明:
Waiting中我修改了get(),分别写成getMain()和getAttach()方法,目标分别是找到主乘客和被捎带乘客(方向与电梯一致的乘客)
Elevator类的run方法变动最大,其while循环中的算法如下:
- 判断此时电梯是否为空,为空,继续,不为空,跳到2
a) 若主乘客为null,结束
b) 设定电梯运行方向为向主乘客运行方向,到达每层时,依次判断是否有出电梯,进电梯乘客
c) 运行至主乘客所在位置,让其进入电梯
- 此时电梯内一定由乘客,从电梯中选出目的地最近的乘客为主乘客,并设置其方向为电梯运行方向(需要判断一下门是否为开)
- 向主乘客目的楼层运行,(期间也要逐层判断是否有出电梯和捎带)
- 运行至目的楼层,主乘客出电梯,(判断有无其它到站、捎带)
以上是我实现捎带的大体算法,由于担心产生负优化,我并没有进行太多优化;另外,我的另一个缺点在于Elevator的类内耦合太高。
二、 自己的bug
由于我这次的优化较少,也没有被发现什么bug
三、 发现别人的bug
由于没有评测机,我感觉这次的bug很不好找,于是就交了几个空刀,但竟然意外的hack到了两个点,我分析可能是因为在处理空电梯寻找主乘客过程中捎带时出现了问题。
第三次作业、多部电梯的调度
一、 分析自己结构
1.需求分析
这次作业主要新增了三个需求,一是限制了电梯载人上限,二是运用多电梯执行任务,三是每台电梯可停靠楼层有了限制。
应对新需求一只需将载人上限设置为电梯参数,要求超出上限时不能进人即可,比较难解决的是需求二和三。
对第二个需求,主要有两种解决思路:
其一,给每个电梯安排一个等待队列,读入新数据立刻分配电梯,每次每部电梯只需类似作业二那样捎带行驶即可
其二,优化一些的算法:给三个电梯只设置一个请求队列,对每个人标记他可以乘坐的电梯,哪个电梯先到达等候者楼层将等候者接上即可,防止了所有人都挤在单个电梯等候队列,而其他电梯却空闲的情况。
对第三个需求,主要解决思路是分解,主要可分解成三种情形:
其一,可直接送达情形,直接接送即可
其二,需要走冤枉路情形:即2-3,3-2,3-4,4-3这四种情形,由于没有直达电梯,必须要走冤枉路(比如上到高楼层换乘再下来),对这四种情况,我单独列出来讨论
其三,需要换乘但不需要走冤枉路情形,则依次遍历A-B,A-C,B-A,B-C,C-A,C-B六种换乘情形,遍历中间楼层,找到可换乘位置并记入即可
另外,其实对二三情况还可以设计一种优化:即在换乘前让二次乘坐的电梯等待该人,可以有效降低电梯折返时间。
2.结构分析
如下图是我的结构
不得不说,这次程序我写的相当烂,不仅没有一点优化(采用了每个电梯一个请求队列的方式),而且还把Input的内聚度弄得极高,还有很多重复性的代码,总之很乱。以下简单介绍一下我的实现方法:
我创建了三个Elevator线程、三个等候队列、和一个Input线程。
Person对象增加了“是否可接送”参数:换乘时,当该人为达第二步换乘位置,该参数为false,当电梯将他送到了换乘楼层,置为true,是换乘的一个关键
Input线程这次变动最大:核心操作还是读入请求并加入等候队列,但修改了加入方式。如上文所述,我将所有请求分为了三种(直达,需换乘需要冤枉路,需换乘无需冤枉路),并根据各自情况,分别按A,B,C的顺序加入A,B,C的请求队列。
Waiting对象的一个大变动是增加了需要synchronized的wake()方法:旨在达到换乘楼层后激活换乘后半部分的Person,使其可接送,但由于可能会与get操作产生冲突,造成线程不安全,故需要加锁。
电梯线程的变动也很大,时间限制和人数限制都可通过传入的参数解决,就不赘述了。电梯操作中另一主要改动是对于换乘乘客需要调用Waiting中wake操作。
二、 自己的bug
我这次暴露出来的bug主要是时间爆了,一部分与我未进行一点优化有关,所有人都挤在最慢的电梯等待,导致时间超出。
三、 别人的bug
很可惜,这次没有找到别人的bug
第二部分 可进一步优化部分
如上所示,第三次作业我可以把所有等候队列都集中在为一个,将可乘坐信息集中在Person中,从而可以防止忙等,另一方面,如果换成电梯为空状态,可以让它到换成楼层等待,从而防止乘客空等。