BUAA-OO第二单元总结

BUAA-OO第二单元总结

作业梗概:
第一次作业:调度1部电梯
第二次作业:调度3~5部相同电梯
第三次作业:调度3 ~ 5部不同型号电梯。电梯类型包括A:所有楼层可停靠,容量最大,运行速度最慢;B:只能到停靠奇数层,运行速度中等,容量中等;C:只能在1 ~ 3、18 ~20层停靠,运行速度最快,容量最小。
三种模式:
random:所有情况均可能出现
night:所有乘客请求同时到达且均前往1层。
morning:所有乘客从1层前往高层,且请求间隔时间不超过2s。

一、同步块的设置和锁的选择

三次作业使用的均为synchronized-notifyall的模式。
第一次作业中,需要加锁的对象为调度器线程与输入线程之间的共享对象waitqueue(总的等待队列),电梯与调度器的共享对processingpassenger。
第二、三次作业中,需要加锁的对象为调度器线程与输入线程之间的共享对象waitqueue,调度器与电梯之间的共享对象waitToPick和 processingpassenger。
加锁对象都是两个线程各自进行读、写操作,可能发生冲突。

二、三次作业中的调度器设计

第一次作业中调度器实现了random、night两种模式,采用了ALS方法算法。读入线程将请求写入请求队列,调度器读取请求队列,并调度电梯前往相应楼层。
第二次作业中调度器将ALS算法改为look算法,其他并未改变。
第三次作业经分析night模式工作时间与random模式相同,将调度模式简化至只有random,其他均相同,且并未进行换乘设计。

三、第三次作业架构设计

UML类图:
image
协作图:
image
可扩展性分析:虽然并未使用工厂模式针对A、B、C类与elevator类实现工厂模式,但对电梯的属性都设置了相应的属性,创建不同电梯之需要声明时更改属性,不需要对其中的方法进行修改。

四、分析自己程序的bug

第一次作业中bug:
主要bug为程序运行时间过长(非死锁,为策略差)。后更改策略通过测试。
第二次作业bug:
出现了死锁,为典型的线程X拿到A锁等待B锁,线程Y拿到B锁等待A锁。未发现的原因在于整个项目中processingpassenger类命名都为passengers,只有该处命名为processpassenger,一定要好好设计变量名称,一定要多做本地测试。
night模式出现了无中生有(即电梯中出现了未进入电梯的乘客),经分析night与random行为基本一致,使用时间完全一致,因此未修改直接换用了random方法。
第三次作业bug:
第三次作业未出现bug

五、分析自己发现别人程序bug所采用的策略

多线程测试难复现,发现别人bug较为困难。主要采用的策略有输入边界数据、阅读代码加锁部分看是否构成死锁。

六、心得体会

多线程设计确实极其费脑筋,特别是第一次作业时对多线程理解不够深刻,设计时确实很费脑筋,但由于第一次作业可扩展性设计较好,也让我体会到了迭代开发的快感,第二、三次作业完成所用的时间更多花费在了修改之前的bug上,改正后完成作业基本在2-3个小时内即可完成,相较于第一单元每次作业都重构然后花费大把时间体验优化了不少。

七、写在最后的碎碎念

本部分主要写一些是想过程中产生过但没有去尝试的想法以及一些注意事项。

  1. 不要交官方输入文档!不要交官方输入文档!不要交官方输入文档!
  2. 多做本地测试! 多做本地测试! 多做本地测试!
  3. night模式设计完经测试时经常会出现第一个请求读入后立即去pick该请求,导致第一次只运送了一个人,后来想到night模式均为高层到1层,所以程序运行伊始就让所有的电梯运行到了2层,在这段时间内完成了调度分配。(后面加入waitToPick队列后不会出现一次只运送一个人的情况)
  4. processingpassenger类比较多余,设计到后面发现其已经是电梯的属性而不是电梯与调度器的共享对象,完全没有必要加锁,笔者因为照搬了实验代码的线程结束设计所以没有更改。(其实是懒
  5. 在程序运行的一些节点输出相应信息能优化debug体验,很多bug往往难以复现,一份log能让你更好的定位bug,且输出得当评测机是会忽略这些信息的。
  6. 关于换乘,笔者最开始是希望能够设计调度器的换乘策略,后发现在不同情况下换乘与不换乘各有优劣,但换乘会产生开关门的固定时间损耗,因此最终采用了不换乘策略。
posted @ 2021-04-25 23:29  Gyy+  阅读(89)  评论(2编辑  收藏  举报