BUAA-OO-Unit2-总结

张雯幻-22230609 学生 2024-04-17 15:45:09

BUAA-OO-Unit2-总结

目录

  • BUAA-OO-Unit2-总结
  • HW5
  • UML类图
  • 架构分析
  • Class 及其复杂度
  • Bug分析
  • 性能优化
  • 同步块设置与锁
  • UML协作图
  • HW6
  • UML类图
  • 架构分析
  • Class 及其复杂度
  • Bug分析
  • 性能优化
  • 同步块设置与锁
  • UML协作图
  • HW7
  • UML类图
  • 架构分析
  • Class及其复杂度
  • 双轿厢的两个轿厢不碰撞的实现
  • Bug分析
  • 性能优化
  • 同步块设置与锁
  • UML协作图
  • 心得体会

HW5

UML类图

img

架构分析

  • 首先有inputThread线程读取输入,将请求给到shcedule
  • 再由schedule根据请求的elevatorId将请求分法给对应id的电梯elevator
  • 最后电梯按照Look策略接送乘客。

Class 及其复杂度

img

可见Elevator类的复杂度较高,因为我的实现方式是让电梯自行决定自己的运动,并没有单独分出一个策略类,这样的好处是实现起来更加容易,缺点是更换策略时更改起来更麻烦。

Bug分析

第五次作业较为容易,强侧中没有Bug。

性能优化

  • 第五次作业中,我第一遍写的是ALS策略,在OO平台提交后发现整体用时较长,很多样例都跑了三十多秒。
  • 所以我后来又改成了LOOK策略,与ALS相比略有提高,弱测样例均降到了三十秒以下。

同步块设置与锁

这次作业的共享对象只有PassengerQueue类,所以我把这个类写成了线程安全的类,多个线程操作时都能保证不会有读写冲突。类当中的每个方法都用sychronized修饰。

UML协作图

img

HW6

UML类图

img

架构分析

  • 这次的乘客请求不再指定电梯,所以就要考虑电梯的分配问题。
  • 首先是新增的Reset请求,为了结构的统一,我令PassengerReset都实现接口Order保持了第五次作业的请求读入部分不变。
  • 在电梯处理请求时增加了先判断请求的类型,如果是Reset请求,就优先进行Reset。当电梯进行Reset时会将乘客丢回总队列,再由Schedule进行派发。
  • 关于电梯的调度策略,我使用的是根据电梯当前的状态计算电梯的优先级,初始每个电梯的Score都是100,根据电梯的方向、楼层、乘客数、等候乘客数等因素进行扣分,最后Schedule会把请求分配给Score最高的电梯。

Class 及其复杂度

img

可见Elevator的复杂度依旧较高,而因为在Schedule中增加了计算电梯优先级分数的操作,复杂度也升高了。

Bug分析

第六次作业的强测中我错了两个点,是同样的Bug。原因是在计算分数时我将Score的初始值设为0,这就导致如果所有电梯的请求都很多的情况下,可能每个电梯的Score都减到了负数,所以调度器找不到要分配的电梯。

所以我将Score的初始值改为了Integer.MIN_VALUE这样就能保证肯定能找到一个分数相对最高的电梯来分配请求。

性能优化

HW7的性能差距主要体现在电梯的分配上,我使用的打分策略的性能分处在中上的水平。但是达不到优秀,主要原因是认为的主观评分很难做到对每种情况的分数控制都能够很精细,这也是无法避免的。至于影子电梯或者随机策略均分策略等我都没有考虑,不了解实现起来是否容易,但影子电梯的性能应该是在我的方法之上。

同步块设置与锁

由于我将ResetPassenger都当做是一种Order存在与第五次作业相同的OrderQueue中,所以没有添加额外的共享对象。

另外再调度器计算电梯的分数时我并没有加锁,一个原因是如果要保证调度器在计算电梯的优先级时让所有电梯的属性保持不变的话需要大量的锁,实现起来太过复杂;并且电梯属性引起的误差很小,不会导师错误,最严重的后果也不过是会延长时间,在容许范围内,所以就没有加锁。

UML协作图

img

HW7

UML类图

img

架构分析

  • 这次作业只新增了一个变化,就是双轿厢电梯,所以我新建了一个DoubleElevator类专门实现双轿厢电梯对象。
  • 当一个Elevator接到DCReset请求时,立即结束自己这个进程,并且在Elevator自己的进程对象中新建并start()两个DoubleElevator进程。并且把自己的属性isDouble设为1,当调度器想访问DoubleElevator时,只能通过原来这个Elevator来访问。
  • DoubleElevator使用的是和Elevator一样的调度策略,因为他们本质上都是电梯,只是能到达的楼层有限制。考虑到DoubleElevator的耗电量更低,所以DoubleElevator的初始Score会高一些。
  • DoubleElevator到达换乘楼层时会将所有的乘客丢出,没有到达目标楼层的乘客会被扔回总队列并改变起始楼层,由Schedule重新分配。

Class及其复杂度

img

双轿厢的两个轿厢不碰撞的实现

对于DoubleElevator可能有的碰撞问题:

  • 首先我在DoubleElevator``wait()前会判断当前电梯是否在换乘楼层,如果在的话就移动到相邻楼层,这样可以保证DoubleElevator不会一直占用换乘楼层。
  • 其次我在DoubleElevator增加了一个锁Lock对象以及一个Flag标志位,当一个DoubleElevator要向换乘楼层移动时会先尝试获得Lock获得后会观察Flag的值是否为True,否则就进行wait()
  • 当另一个电梯从换乘楼层离开时会对Lock执行lock.notifyAll(),并把Flag设成True,这样如果另一个电梯也想进入换乘楼层的话就会被唤醒,并再次把Flag设成Flase代表换乘楼层有电梯。
  • 这样就能保证电梯不会同时到达换乘楼层。

Bug分析

第七次作业中我的强测没有错误,但是有一个hack,原因是一个调度器提前结束的小问题,当时被我忽略了。

性能优化

这次作业的调度策略与HW6相同,没有额外的优化。

同步块设置与锁

这次作业中我发现了一个锁的问题,如图:

img

原来我没有最外面那一层的sychronized,因此有一个Bug就是当我从OrderQueue中取出一个Order对象赋给order时,这时如果OrderQueue为空,因为order还没有来得及存到电梯自己的队列中,所以此时Schedule就会认为当前所有队列都是空的,因此提前结束导致错误。所以加了一层OrderQueue的锁来避免这个问题。

UML协作图

img

心得体会

经过这一单元的学习,初步掌握了多线程的运行模式,可以完成简单的多线程任务。也体会到了共享保护在多线程程序中的重要性,以及锁的使用也是掌握内容的一部分。

...全文
66 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧