本单元共三次电梯系统设计做业,难度递增,架构能够层层嵌套(每次都设计好的话),趣味颇丰。电梯的款式(奇怪的描述)均为目的选层电梯,即乘客可在电梯外发送本身想要去的楼层。java
乘客的请求包括出发楼层和目的楼层与id,每位乘客都有本身独有的id,一个id只能对应一个请求,本单元不需考虑WF检测。算法
第一次做业电梯名为单部多线程傻瓜调度(FAFS)电梯。傻瓜调度就明确指出不须要关注电梯性能,只须要完成接送人的任务,所以我菜用了较为直观的设计思路:安全
电梯属性包括:1个请求队列(属于本电梯还在电梯外某楼层等着的人)、1个电梯内部队列(电梯内部的人)、电梯如今的楼层。性能优化
类设计包括:Main(轮询接受输入)、Elevator(执行单元)、Waiter(请求类)、Inner(电梯内请求类)。共4个类多线程
运行逻辑以下:架构
一、Main函数轮询(输入接口等待输入,无输入时阻塞不占用CPU)接受输入的请求,将请求发送给电梯。函数
二、若输入NULL,则由Main函数向电梯发送中止信号。性能
三、电梯轮询依次判断如下内容:测试
(1)、若电梯内部队列不为空,则执行电梯内乘客请求(将乘客送至指定楼层)优化
(2)、若请求队列内如有请求,则执行该请求(电梯先去接乘客,而后将乘客送至指定楼层)
(3)、轮询结束条件:请求队列为空 && 电梯内部队列为空 && 接收到中止信号
总结:本次做业未使用调度器(确实一开始没想到有这种高级策略),但由于本次做业较为简单,并未受到影响。了解到了ArrayList线程不安全,以及简单的多线程运行逻辑,为第二次做业铺设了基础。
本次做业电梯名为单部多线程可捎带调度(ALS)电梯。可捎带是本次做业核心,如何完成“捎带”成为本次做业的难点。设计架构沿用第一次傻瓜电梯的架构(可贵的没有重构),设计思路以下:
电梯属性包括:1个请求队列(属于本电梯还在电梯外某楼层等着的人)、1个电梯内部队列(电梯内部的人)、电梯如今的楼层。(彻底沿用第一次的电梯架构)
类设计包括:Main(轮询接受输入)、Elevator(执行单元)、Waiter(请求类)、Inner(电梯内请求类)。共4个类(彻底沿用第一次的电梯架构)
电梯执行逻辑:电梯只执行主请求(电梯内最先进来的那我的),即电梯内部队列里的第一个元素。
接人逻辑(捎带判断):接人的条件需知足如下条件:(1)、捎带请求与电梯主请求同方向。(2)、捎带请求的出发楼层位于电梯主请求出发楼层与目的楼层之间(电梯到达某一楼层后,经过对请求队列的循环判断来实现,若知足条件,则执行捎带)。
运行逻辑以下:
(电梯每到一层,对请求队列循环判断)
一、Main函数轮询(输入接口等待输入,无输入时阻塞不占用CPU)接受输入的请求,将请求发送给电梯(将接受到的请求加入电梯的请求队列),并唤醒电梯(执行notify)。
二、若输入NULL,则由Main函数向电梯发送中止信号。
三、电梯非轮询依次判断如下内容:
(1)、若电梯内部队列为空 && 请求队列为空 && 未接收到中止信号 :电梯执行wait()操做(电梯线程由执行态转换至waiting态,等待被notify)
(2)、若电梯内部队列不为空,则执行电梯内乘客请求(将乘客送至指定楼层),同时进行捎带判断。
(3)、若请求队列不为空,则执行该请求(电梯先去接乘客,而后将乘客送至指定楼层),同时执行捎带判断。
(4)、电梯中止运行条件:请求队列为空 && 电梯内部队列为空 && 接收到中止信号
总结:本次电梯主要难点在于实现捎带逻辑,个人捎带逻辑也许不是最优化的(从系统总运行时间来讲),但能够知足题目的要求。本次实验了解了wait()和notify()的使用方法,初步接触了 synchronized关键字的使用,利用先有请求后执行这一逻辑避开了“电梯wait但无人唤醒”的状况,本次做业作完以后才了解到“调度器”这一律念,虽然没在此次做业中体现,可是提早完成了调度器的设计,为第三次终极智能电梯打好了基础。
此次实验因为个人疏忽大意(arrive输出时间疏忽),强侧分数有点恶心,可是整体上玩的仍是很开心。
本次做业电梯名为多部多线程智能(SS)调度电梯。“多部”、“智能(电梯已是成熟电梯了,会本身分辨请求了)”是本次做业核心。电梯的设计架构沿用第二次捎带电梯的架构(可贵的再次没有重构),同时实现了调度器线程,调度器与电梯存在上下级的关系,设计架构以下:
本次电梯与前两次电梯具备电梯属性的不一样,包括如下内容:电梯容量,电梯可达楼层,不一样电梯速度不一样(和调度策略的设计有关)。
电梯属性包括:1个请求队列(属于本电梯还在电梯外某楼层等着的人)、1个电梯内部队列(电梯内部的人)、电梯如今的楼层、电梯名、电梯容量、1个电梯可达楼层的ArrayList(方便使用contains方法)。(部分沿用第二次的电梯架构)
类设计包括:Main(轮询接受输入)、Elevator(执行单元)、Waiter(请求类)、Inner(电梯内请求类)、Dispatch(调度器)。共5个类(部分沿用第二次的电梯架构)
电梯执行逻辑:电梯只执行主请求(电梯内最先进来的那我的),即电梯内部队列里的第一个元素。
接人逻辑(捎带判断):接人的条件需知足如下条件:(1)、捎带请求与电梯主请求同方向。(2)、捎带请求的出发楼层位于电梯主请求出发楼层与目的楼层之间(电梯到达某一楼层后,经过对请求队列的循环判断来实现,若知足条件,则执行捎带)。
调度原则:Main函数发送请求给调度器线程,调度器线程将请求存入调度器内请求队列,将请求根据须要分红4个请求:一、乘客可乘A电梯直达目标楼层。二、乘客可乘B电梯直达目标楼层。三、乘客可乘C电梯直达目标楼层。四、乘客须要换乘,执行换乘逻辑。
调度器换乘逻辑:根据三部电梯的可达楼层分析,乘客在起始楼层和目标楼层之间选择一部换乘电梯并选择一个换乘楼层(以先A后B后C原则,由于A电梯最快,这个的算法并很差),而后将乘客标记为须要换乘,将请求发送给电梯。
电梯换乘逻辑:若电梯发现将要出电梯的某乘客为换乘乘客,则向调度器发送一个新请求,将换乘乘客信息从新发送给调度器(即将换乘楼层变动为起始楼层,目标楼层不变,乘客id不变),新请求将唤醒调度器,并执行调度器内换乘乘客计数器--(加锁)。
调度器使用单例模式,即私有构造并设立getinstance()方法。
一、Main函数轮询(输入接口等待输入,无输入时阻塞不占用CPU)接受输入的请求,将请求发送给调度器(将接受到的请求加入电梯的请求队列),并唤醒调度器(执行notify)。
二、若输入NULL,则由Main函数向调度器发送中止信号,并结束Main函数。
一、若调度器请求队列为空 && (未收到Main函数发出的中止信号 || 存在换乘乘客) ,则执行wait()操做,等待被唤醒。
二、从调度器请求队列中取出一个乘客,将该乘客根据调度原则,将请求分配给三个电梯中的一个(每一个电梯都有本身内部的请求队列,即该电梯可以接的人,电梯对于调度器请求队列一无所知),并从调度器请求队列中移除该请求。若发现乘客须要换乘(执行调度原则4),则将调度器内换乘乘客计数器++(加锁)。
三、若调度器请求队列为空 && 收到Main函数发出的中止信号 && 不存在换乘乘客 ,则向三部电梯发送中止信号,并中止调度器线程
电梯非轮询依次判断如下内容:
(1)、若电梯内部队列为空 && 请求队列为空 && 未接收到中止信号 :电梯执行wait()操做(电梯线程由执行态转换至waiting态,等待被notify)
(2)、若电梯内部队列不为空,则执行电梯内乘客请求(将乘客送至指定楼层),进行捎带判断,进行电梯换乘逻辑判断。
(3)、若请求队列不为空,则执行该请求(电梯先去接乘客,而后将乘客送至指定楼层),进行捎带判断,进行电梯换乘逻辑判断。
(4)、电梯中止运行条件:请求队列为空 && 电梯内部队列为空 && 接收到调度器发出的中止信号
设计思路:此次换乘电梯最终构想是将换乘乘客标记,等到须要换乘时,由电梯向调度器输送请求,可是这么设计是不符合实际的,应该由调度器统筹安排电梯,电梯做为执行单元,不该该影响调度器的工做,但由于我的能力有限,确实没能想到一个好办法,实现和电梯低耦合关系的调度器。
总结:本次电梯主要难点在于实现换乘,个人调度逻辑有大优化空间,可是由于我的能力有限,就没有追求性能优化(怕改很差改出一堆bug)。个人换乘方法决定了个人调度器的中止条件,这个中止条件是经历了不少次输出debug才最终肯定的,确实对于多线程的理解有了很大帮助。很感谢助教团队的辛勤构思,要否则我是没有这个自信,仅仅第二次做业,就完成“不重构代码”这一重大进步。此次的方法复杂度教前两次有了一个明显提高,但我设计调度器以前,就尽量下降调度器和电梯的耦合性,可是最后没能想出一个较好的办法,他们之间仍是存在双向的信息传递。
第一次第二次做业bug主要在于,输出方面的小瑕疵,尤为是第二次做业,在输出到达楼层和开关门之间,很容易有逻辑上的疏忽。
第三次做业bug主要在于换乘,换乘的是否合理,是否存在“电梯杀人状况”,是否存在“电梯过早中止的状况”,这是我遇到的bug中较为典型的
多线程bug单步调试已经很难进行,因此采起了输出调试的办法,这种办法也是比较高效的,较好的解决个各类bug。
多线程程序会出现,bug存在可是很难复现的状况,因此找到一组比较好的数据,进行屡次提交,能够较好的找到一些“强测幸存者”。
电梯单元让我清晰了解了java多线程的精妙,很明显的感受到本身在一次一次做业中,逻辑不断完善,设计思路不断清晰。线程安全类的使用,物理锁与逻辑锁的使用,线程唤醒的细节,都是在一次又一次试错中慢慢摸索到的。用一个数据屡次测试本身的程序,有时会出现bug,可是再复现起来可能要通过不少次的调试,这个过程是艰难的,但发现bug并成功解决收获的快乐和知足,也是很难用言语形容的。只有每次做业都尽心尽力,才能感受到本身在不断进步,之后的oo做业也会更努力的。