OO课程第二单元总结

第一次作业

第一次作业是模拟单部多线程电梯的运行。
尽管单部电梯的实现依靠单线程就可以完成,但是为了便利后续的迭代开发,建议还是从一开始就使用多线程来进行设计。
通过参考课上实验代码,比较容易就能设计出本单元的整体架构。

  • 总体架构

    image
    参考实验课给出的代码,我在三次作业中使用了类似的架构(如上图所示)。在此先对各个类进行一个简要的说明:

    • MainClass:创建相关子线程,并从官方输入包中读入请求至WaitQueue
    • WaitQueue:存储未处理请求,由SchedulerThread将请求分配至各个电梯。
    • SchedulerThread:中心调度器,将WaitQueue中请求逐一分配至各个电梯的ElevatorQueue
    • ElevatorQueue:存储某电梯需要处理的请求,由ElevatorThread进行处理。
    • ElevatorThread:电梯线程,对本电梯所负责的ElevatorQueue进行处理。
    • Elevator:电梯的静态类,存储电梯包括容量、已搭乘乘客等在内的信息。
    • Methods:抽象类,内置于ElevatorThread内部,有若干子类,按照计划应该根据状态的不同,使电梯执行不同的策略。
  • 策略分析

    • 在该次作业中,我原计划对每种时间状态写一个电梯的运行策略,分别是MorningMethodRandomMethodNightMethod
    • 参考磁盘相关算法,RandomMethod使用SSTF调度策略,优先处理与电梯位置最近的请求进行处理;NightMethod使用LOOK调度策略,该策略在实际生活的电梯中具有广泛的应用;MorningMethod的理想策略实现更为特殊,由于时间所限,因此我只是在LOOK调度策略上进行了一点微不足道的优化。
    • 在实际测试中发现,RandomMethod稳定性较差,在中测中就会超时,当然也可能是因为我细节上实现地不够好。最后RandomMethod也使用了LOOK算法。
    • 此外,在存储乘客请求时,先对请求的出发层进行归类,再对请求是否上下行进行分类,最后按照目标层高低进行排序。这样的存储方法可以尽可能地让乘客请求相对集中,便于统一的处理。
  • 调度器设计

    • 在该作业中,调度器只是将请求单一地从WaitQueue中移动至单部电梯的ElevatorQueue中,没有起到实质性的作用。
    • 在该次作业中,我将策略类内置于ElevatorThread,根据不同的时间选择不同的策略,使电梯做出不同的运行行为。
  • 同步块的设置和锁的选择

    • 在本次作业中,我只使用到了synchronized关键词对对象进行加锁。
    • WaitQueueProcessQueue类是两个“托盘”,而本作业中的两个主要的线程——SchedulerElevatorThread在读写“托盘”中的信息需要加锁,从而降低了耦合,也有利于初学Java线程的我们写出更少的BUG。
  • BUG分析

    • 该次作业在强测与互测中都未发现BUG。
    • 我也没有在互测中发现别人的BUG。

第二次作业

第二次作业是模拟多部多线程电梯的运行,且中途可以动态添加电梯。
第二次作业只需要在第一次作业上的基础上增设一些新的电梯即可。

  • 策略分析

    • 在该次作业中,我意识到不应该对每个电梯线程内置策略,而应当在调度器中内置策略,充分发挥调度器的作用。
    • 原先内置于ElevatorThreadRandomMethodNightMethodMorningMethod被移除,使用同一的GeneralMethod,实现LOOK算法,来实现电梯的运行。
    • 一种直观的想法是:调度器获取各个电梯的状态,将请求分配给能够最快响应当前请求的电梯。此外,还应当考虑到电梯的负载情况,尽可能将请求平均地分给各个电梯。
    • 由于可能中途增加电梯,且电梯可能满员而无法完全接受请求,因此我构思了一种回收模式,将当前电梯短时间内无法响应的请求重新回收到WaitQueue中,由SchedulerThread重新进行分配,从而充分利用电梯。电梯每运行一次,进行一次回收,回收的对象为与当前电梯运行方向相反一侧的楼层内的全部请求。
    • 对于不同的时间状态,我认为Random模式与Night模式没有太大的区别,需要让电梯处于较低的负载状态。而在Morning模式下,由于回收机制的存在,可以考虑对电梯进行高负载的请求输送。当电梯满员后,剩余请求将重新被分配给其他电梯,从而提高电梯的运行效率。
  • 调度器设计

    • 在该作业中,调度器需要根据请求与各个电梯状态,智能地将请求分配给各个电梯。
    • 在之前的架构中,SchedulerThread只能访问WaitQueueElevatorQueue。而ElevatorQueue中不包含电梯的信息,因此在上述的策略中,SchedulerThread还需要与Elevator建立联系。
  • 同步块的设置和锁的选择

    • 在这一次作业中,调度器需要额外对Elevator进行访问。不过值得庆幸的是,这一访问只是读取,不会写入,又由于有回收机制的存在,也不用担心请求被错误分配,因此实际上不需要对Elevator额外加锁。
    • 实际上将Elevator设置成线程安全类也会很方便,但我又懒又担心这会增加程序运行时间。按照规范理应是需要将Elevator进行加锁处理的。
  • BUG分析

    • 该次作业在强测中发现了一个很致命的BUG。在动态加入电梯时,我没有增加表示电梯数量的变量numOfElevator,导致在加入第二个电梯的时候,前一个电梯的属性将会被后一个所覆盖,从而产生了BUG。这一BUG直接导致我WA了一半的强测点。当然这也反映出我没有做足够的课下测试,以及对中测的数据过于自信
    • 由于对多线程程序测试经验的不足,手动构造样例的方法十分低效,我也因此没有在互测中发现别人的BUG。

第三次作业

第三次作业在第二次作业的基础上,对电梯的型号进行了补充设定,不同型号的电梯到达楼层、容量、运行速度等都有差异。
考虑性能,第三次作业最好能够实现电梯的换乘,使得乘客能够尽可能快地抵达目的地。

  • 策略分析

    • 第三次作业对调度器的要求更高,我几乎是重新写了调度器的调度策略。
    • 我使用的是一种打分制的策略,对于一个请求,首先考虑哪些电梯能够接收它,从响应该请求所需的时间电梯自身负载状况该电梯完成该请求所需时间三个角度进行分析,给出一个loss分数,选取loss分数最小的电梯搭乘该请求。此外,还应该筛选出该请求可能的换乘方案,考虑换乘时完成该请求所需时间,并加上一个换乘惩罚系数作为loss函数,综合比较后分配请求。
    • 由于精力有限,各部分的权重参数都是我脑测随意取的数字,性能上达不到最佳,但较一般的调度方法应该会有一定优势,对于应付强测已经足够。此外,对于不同的时间模式,我也没能进行针对性的优化。
    • 在实际运行时,会出现请求多次反复换乘的情况,甚至会造成死循环。我当时粗暴地对请求添加了一个换乘次数的参数,对于换乘次数大于1的请求,则不允许其再次换乘。现在想想也许可以将其作为参数加入到换乘惩罚的计算中,或许会更为合理。
  • 调度器设计

    • 与上一次作业基本相同。
  • 同步块的设置和锁的选择

    • 与上一次作业基本相同。
  • BUG分析

    • 该次作业在强测与互测中都未发现BUG。
    • 我也没有在互测中发现别人的BUG。
  • 可扩展性分析与总结

    • UML类图

      image
      私以为程序之间的逻辑联系还是较为清晰的,这有利于后续的功能拓展。

    • UML顺序图

      image

    • 可扩展性分析

      我认为我的程序有一定的可扩展性。呃,实际上如果能够实现第三次作业的要求且没有出现太大的错误的情况下,我相信大家的程序都有较好的可扩展性。关键在于后续的要求是否繁琐。如果只是单纯的增加减少电梯,那想必不会存在太大的问题。如果加入负数层电梯,因为我在存储楼层的时候使用的是Hashmap,也只需要对电梯跨越0层的时候进行稍许的处理。如果电梯没有型号的限制,所有电梯相关的信息都是在程序运行时才给出,那我则需要从头写调度器策略,而从一开始使用图论来求最短路径的同学则会减少较多的工作压力。至少在我想象力所及的范围内,绝大多数的要求都不会需要我对程序进行重构,这也许能算得上是较好的可扩展性?

心得体会

本单元的多线程作业依然有着较高的难度,但多亏了第一单元的洗礼,让我对Java语言本身有了更为深刻的理解,因此我认为本单元在总体难度上反而低于第一单元。在理解了多线程的概念后,自己动手写多线程程序其实并不困难,但也要小心线程安全的问题。在第一次作业之前,我深入了解了线程安全的注意事项,掌握了简单的锁的概念,学习了死锁会出现的原因,因此在本单元的三次作业中,并没有出现线程安全相关的错误。只有在第一次作业中,出现了线程无法结束的状况,但也最后顺利解决了。在层次化设计上,我认为我在写代码的时候也体现了一定的类似的思想。在写第一次作业的时候,我就构思好了程序的大致框架,划分了不同类的职责,因此在后续开发上节省了不少功夫,也没有中途重构。虽然多线程作业结束了,但我只是简单地了解了多线程,研讨课上同学分享的许多内容与概念还值得我去深入地学习。

posted @ 2021-04-27 18:49  Synotp  阅读(50)  评论(0)    收藏  举报