OO-第二单元总结-2021

Unit 2:电梯-单元总结

一、同步块和锁的设置

所有同步块和锁集中在调度器Scheduler中,包括:

  • 存放所有电梯请求的requestByFloor请求存储容器(同步容器)

    为了方便分层查找同时保持线程同步,使用ConcurrentHashMap<Integer, CopyOnWriteArrayList<PersonRequest>>,其中key为楼层,value为该楼层待服务的请求。

    • 在第七次作业中,电梯存在不同类型。为了方便调度,我在初始化请求时就确定每个请求的乘坐电梯或换乘方式(如果有必要的话),并将其加入requestByFloorArequestByFloorBrequestByFloorC三者之一,表示即将被A或B或C类型的电梯服务。
  • 添加请求方法addRequest

  • 获得主服务请求方法getMain

  • 获得当前层能捎带的请求方法getSubRequests

    • 以上三个方法在第五次、第六次作业中均以synchronized方式在方法上加锁。
    • 在第七次作业中,由于涉及到三个请求存储容器,不能再对方法整体进行上锁。使用方法为先设置一个局部变量requestByFloor为当前要进行操作的请求存储容器,再对该局部变量以同步块的形式进行上锁。

二、调度器设计与线程交互

第五次作业一开始调度方法基本上可称为随机调度(0__0),bug分析部分会详细说明。第五次作业bug修复后以及后两次作业中采用相同的调度策略,在调度器设计上主要框架为ALS可稍带法则,每次先选择主请求,选择好后再根据主请求在经过的每层选择捎带请求。

对ALS法主要的修改为,在挑选主请求时(无论是在电梯内有人或无人时),都尽可能选择所在楼层距当前楼层最远的待服务请求。从后两次作业强测s性能得分上来说,算法表现是可以接受的。

三、架构设计

UML类图和顺序图

hw5

UML类图

image-20210423153500403

UML时序图

PlantUML diagram

hw6

UML类图

image-20210423151804014

UML时序图

PlantUML diagram

hw7

UML类图

image-20210422121029213

UML时序图

PlantUML diagram

架构设计的可扩展性

三次作业之间的递增关系在本单元作业中还是很明显的。本单元没有经历重构。

第六次作业在第五次作业之上,只添加了一个ElevatorBoss类用来添加电梯和整体管理所有电梯,其他没有修改;第七次作业由于涉及换乘新增了一个PersonRequest的父类PRequest及相应的电梯类型分配。

四、自己的bug分析

第五次作业

  • 强测和互测出现大量RTLE,原因是没有注意到指导书中的时间限制,以为只要把人送到指定楼层即可。于是,在中测时,我使用的调度算法基本可以称为随机分配。而后将其修改为在第二部分中提到的修改的ALS算法,即解决。

第六次作业

  • 互测没有出现问题

  • 强测中有两个点出现RTLE:

    • 其中一个出现的情况是:在一层的请求进入电梯时,一旦电梯满员会直接return,而如果此时确定的主请求恰好还未进入电梯,则电梯内无主请求会进入wait状态导致死锁。故解决方式是当电梯满员就检查当前的主请求是否已进入电梯,如果未进入,则需要在电梯内重新确认主请求。
    • 另一个出现的情况是:比如0.0s时有5个从第1层出发的请求应该进入电梯,当我的电梯在一层开门时,却只有小于5个请求进入了请求队列;其余的在电梯检查后才能进入请求队列;于是当时间卡得紧时,就会出现RTLE。问题的原因是在同一时刻请求输入线程还未完成该时刻的输入时就被电梯线程抢夺锁。虽然几经尝试,但该问题目前还没有解决。

第七次作业

  • 互测强测均未发现问题。

五、发现bug的策略

测试策略

从第六次作业开始在中测自我测试时会记录下自己程序曾有过问题的数据集作为部分互测数据资源,同时通过阅读对方代码和评测机进行互测。(第五次作业在中测结束后不久就发现了自己程序的巨大漏洞,于是就开始de自己的bug,没有很集中的进行互测)

线程安全问题的发现

  • 首先在程序逻辑上确认自己没有暴力轮询。
  • 一旦程序没有办法成功停止即出现死锁,使用JProfiler和断点调试的方式对死锁进行定位。

与第一单元测试方法的差异

  • 最大的差异就是第一单元是单线程,而本单元是多线程。
  • 由于多线程运行存在不稳定性,有一些较为隐蔽的bug一次出现后较难复现。解决方式一个是使用评测机大量投放,确保测试的全面性;另一方面就是在断点调试时在断点处考虑是要打断线程还是打断程序,可能会导致不同的结果。

六、 心得体会

电梯完结撒花!!

今年相较于去年来说,新添加的三个模式并没有制造什么障碍,只需在调度算法稍加考虑就不必特别处理。

关于线程安全

本单元的主要难点集中在线程安全的处理上。尤其第七次作业在拥有针对三种类型电梯的三个等待队列后,如何在适当时候使电梯线程进入wait或者终止程序运行至关重要。

关于线程安全,我认为的重点有:

  • 加什么锁?
    • synchronized
    • concurrent包中的线程安全容器
    • 读写锁...
  • 对什么加锁?
    • 对方法整体加锁
    • 用synchronized代码块对某个变量加锁
  • wait和notifyAll的配合,避免轮询和死锁

关于层次化设计

在本单元的学习中对多种设计模式有了一定的了解。在作业中,由于电梯线程-调度器-输入线程之间的关系,自然地使用了生产者-消费者模式。三次作业中,也经历了从单消费者到多个同类型消费者再到多个不同类型消费者的转变。

总体来说,我对多线程编程有了较为细致深入的掌握,同时对多线程设计模式、状态模式以及死锁问题的解决都有了一定了解,收获颇丰。

posted @ 2021-04-26 21:42  aucu1608  阅读(78)  评论(0)    收藏  举报