BUAA_OO_第二单元总结
作者:互联网
BUAA_OO_第二单元总结
第二单元主要实现电梯的调度问题。主要为了实现单部电梯、多部电梯、横纵向电梯的调度。
第一次作业
作业要求
第一次作业要求完成纵向电梯第调度问题。五个楼座各配置一部具有一至十层移动能力的电梯。电梯具有固定的移动速度、开关门速度和承载量。
代码分析
- 类图
- MainClass为程序入口,调用MainController获取输出并且分配给各个楼座。
- MainController获取输入,同时将请求分发给各个楼座。结束时,唤醒和设置电梯结束标识符为真。
- Controller服务单个楼座的电梯,获取主控类的乘客请求,放入WaitQueue类,同时为Elevator类和WaitQueue类提供交互,检查捎带、提供捎带乘客、制定电梯新策略。
- WaitQueue保存单个楼座的侯乘表,实现捎带与先入先出的请求获取方式。
- Strategy类为单个电梯的策略类,保存了当前电梯的最远目标楼层,各层的开关门信息和运动方向。
- Passenger类保存了单个电梯内部的乘客。
- Elevator类为单个电梯,能够根据策略类的信息进行移动。到达楼层后检查捎带并使乘客进出。
- OutputHandler为输出类,保证线程安全。
-
时序图
-
锁分析
本次作业的锁为sychonized同步锁。WaitQueue、Elevator、OutputHandler上有同步锁。
WaitQueue的锁用在Controller中添加请求、取出捎带乘客两个方法中,分别对应了对WaitQueue类的写入新请求和删除请求。
Elevator的锁用在Controller和Elevator类中。COntroller对于电梯的制定策略、检查捎带和取出捎带乘客方法获取了锁。Elevator的run方法对于本身进行加锁。实际上Controller类中对于电梯的操作都是由Elevator的run方法调用的,无需加锁。
OutputHandler类对于所有方法都进行了加锁,保证了输出时的线程安全。 -
调度器分析
本次作业调度器为Controller类。调度器的主要功能是输入请求、输出乘客和策略。
首先是输入请求,通过MainController输入一个乘客请求,同时将请求输入给WaitQueue,根据楼层和目标楼层进行分类。
输出策略为在制定新策略和检查捎带。两个方法通过电梯来进行调用。新策略制定是在电梯无请求时通过当前的运动方向优先进行同方向运动,否则反方向运动,若无候乘停止。检查捎带是在运动过程中检查该楼层是否存在同方向乘客。
输出乘客方法由电梯调用,取出该楼层该方向上的请求,进行捎带。
BUG分析
本次强测和互测出现了两个bug。第一个是由于输出线程不安全所导致的bug,通过建立了OutputHandler类的锁进行了解决。第二个是由于电梯运动时始终利用持有锁,导致了Controller在获得乘客的输入请求后无法对电梯进行notify而导致的阻塞,因而发生了超时。在修复时采用每次notify时都创建一个新线程来等待阻塞结束再notifyAll,虽然通过了,但是在后续作业中留下了bug。
第二次作业
作业要求
本次作业相较于第一次作业主要增加了横向电梯与随时增加电梯的功能。
代码分析
- 类图
- 本次主要是对于电梯类、候乘类和控制器类进行了抽象,同时实现了楼层和楼座的电梯、候乘、控制器来继承。
- 时序图
本次作业的线程的运行方式与第一次作业相同,故时序图相同。 - 锁分析
本次作业应用的锁较第一次作业增加了一个Lock类锁。主要用在电梯类中,来标识电梯本身是否持有自己的锁。以此在别的类中需要notify电梯类时,可以先尝试获得锁,不能获得则表明电梯正在运行,不需要notify,防止了类似第一次作业因notify电梯而阻塞的bug。 - 调度器分析
本次的调度器与第一次作业相同,只不过在横纵向电梯的调度策略上采取了不同的策略。楼座电梯上仍使用了LOOK策略。但是楼层电梯上使用了类似于ALS策略,只搜索了本楼座上同向的请求,并没有搜索同一方向上别的楼座的同向请求。
BUG分析
本次作业的BUG是由于第一次作业修改后留下来的BUG。由于多开线程等待阻塞而导致了线程过多的问题。因而就用上述的Lock锁来解决的阻塞问题。
第三次作业
作业要求
本次作业要求能够定制电梯的部分参数,并且支持电梯的换乘。
代码分析
- 类图
- 本次作业在类上与第二次作业相同,没有增加新的类。故类图与第二次作业基本一致。
- 在Elevator类中改变了部分常量,如运行速度、可到达楼座等。
- 在FloorController类中进行了改变,要求能够储存所有该层电梯的可到达楼层。
- 在MainController类中addRequest方法中进行了改变,支持了换乘。
- 时序图
- 锁分析
本次作业对于第二次作业的锁进行了改进。第二次所加的Lock锁本身就是为了解决互斥电梯类的问题,synchronized(elevator)因此可以改进为synchronized(lock),同时缩小synchronized的范围。 - 调度器分析
本次调度器与第二次作业相同。
对于换乘方面的调度则是先制定换乘的策略。优先选择在起始楼层或者目标楼层换乘,其次再考虑在起始和目标楼层之间的某一层换乘,最后考虑其他方法。在调度时先制定策略,放入策略中的第一部电梯。电梯会将乘客运送到换乘或者目标的楼座或者楼层,然后检查是否到达目标位置,若未到达则放回主控类中再次计算换乘策略。
BUG分析
本次bug主要还是出现在上一次的修复中。因为lock的引进,使得控制器唤醒电梯时先lock再synchronized(elevator)和电梯恢复时先synchronized(elevator)再lock发生了死锁。因而将这一部分进行了修改。
单元总结
测评方法
本单元采用的测评方法仍是自动测评。利用python来进行输入的生成和结果的检验。利用python的随机数来生成测试点,生成非递减的时间和不同的请求。同时将数据进行输入,写入结果至文件中。然后进行结果的比对,检查时间的顺序、电梯运动的正确性和乘客是否到达目的地。并且利用官方的计算和ALS策略计算出最长时间,验证是否超时。
这一测评方法也被利用于互测中,检查出了部分同学死锁或者没有到达目的地的问题。同时也检查出自己程序的部分输出问题。
感想总结
从架构上来看,本次的架构可拓展性较好,没有进行大规模重构。在每次作业的拓展中大部分只是进行了抽象和方法的更改,没有较多的改变。代码的层次性还行,类间的区分较大,参数的设定正确。但是类间的方法相互交错,经常需要在不同的类间不断地调用相互的方法,感觉可以进行进一步优化。
从线程上来看,线程安全的主要问题就是互斥和死锁问题。互斥的方式利用锁就较容易解决。但是死锁的问题严重,较难发现。因而一是需要检查代码的逻辑,找出锁的嵌套,谨防死锁。第二是应该做出大量的数据测试,来保证大部分情况下的线程安全。
从修复上来看,对于bug的修复不彻底而遗留下的问题让我在多次作业中都受到了攻击。在bug修复的时候,改变了部分参数、类时,应当继续考虑整体的逻辑,找出可以通过优化而改变的点,保证代码的流畅性而非只是单纯的进行漏洞填补。
标签:OO,请求,作业,BUAA,楼座,电梯,楼层,线程,单元 来源: https://www.cnblogs.com/wwz-buaa/p/16204869.html