BUAA_OO_2022 第二单元总结

面向对象设计与构造 第二单元总结

总述

第二单元主要是Java多线程的实现,自我感觉第二单元的作业比第一单元的实现轻松不少,但每次作业最终的实现效果并不十分让人满意。虽然有过在debug过程中找不到CTLE和RTLE错误原因的"坐大牢"环节,但最后我发现多线程问题的解决主要还是对线程的理解和对调度方法的完备思考。三次作业中出现的bug分别是轮询和调度问题,第三次作业中仍然发现在第二次作业之后还是没有完全改对的错误。总体而言由于自己课下测试较少,代码中潜在的"明显bug"没有及时找出,对多线程的理解需要进一步加深。

第5次作业

实现思路与架构

第五次作业的实现主要参考了实验3中的内容,但基于这次作业并没有过多的电梯,没有使用控制器调度请求,而是直接在输入时将请求投入到相应的队列中,直接分配进行调度。主要的实现为一个input输入线程,5个电梯线程。输入线程将请求加入到每个电梯对应的请求队列中,然后电梯根据请求队列和自己电梯中的队列进行相应运行操作和人员进出操作。

在电梯调度策略中,我使用的主要是look算法,且根据当前时刻电梯中是否有乘客对电梯进行上下运行调度。

UML图

 

 

协作图

 

Bug分析

第5次作业主要的bug是没有注意轮询的问题,导致ctle错误的产生。在互测中又发现输出方法类没有上锁,时间戳可能输出有误。错误的产生还是对多线程的不熟悉。

第6次作业

思路分析与架构

第六次作业新增了横向电梯调度和新增电梯。这次作业我大体按照第5次作业的思路进行电梯类的扩充,将电梯扩充为横向和纵向两种。横向电梯和纵向电梯的调度大致相同,只是在电梯中没人时接下来的运行方式需要多加考虑。我在这里的处理中出现了一点问题,在强测和互测中都被发现此问题可能产生死循环。而此问题并未在第六次作业中修改完美,导致第七次作业中又发生了另一种方式的错误。

对人员请求的处理中,我并未采用自由竞争的方式,而是为每个电梯都创建一个单独的请求等待队列,将相同种类的电梯请求队列添加到一个更大的队列中。当有请求加入时随机将这个请求分配到相应大电梯请求类的请求队列中,这种调度分配方式的最终运行结果尚可,和自由竞争相差不大。

UML图

 

协作图

 

Bug分析

这次作业的bug出现在电梯调度上,我是用的类look算法中“顶层”和“底层”对应的楼座是动态变化的,导致当电梯中没有人员且需要新加入捎带时,可能会出现电梯死循环调度的情况。在添加了特殊调价判断后通过了这次作业的评测,但是这里的bug并没有完全解决,在第七次作业中bug又浮现出来,最后只好采用将所有同一方向的请求全部处理完成后再处理另一方向的请求,虽然性能有所下降,但是好像也没找到更好的非重构修改方法。

第7次作业

思路分析与架构

第七次作业混合调度不同的请求,开始时我采用的架构是在第6次作业的基础上直接进行处理,但最后发现请求处理完之后所有线程进入阻塞状态,没有能够继续将其成功的更改过来。最后采用类似exp4-2的终值进程的方法。

这次作业中重新构建了personalrequest类,在请求类中添加了中转楼层、当前状态、当前出发和目的楼层楼座信息,为更好的适应这次作业的实现。

对于每个人员调度请求,我采用类似流水线方式。每个请求在输入时根据当前的所有电梯找到最佳的中转楼层,静态分析当前请求应途径的状态变化和当前所在的状态,再将这个请求投到对应的电梯队列中。当这一阶段的请求处理完后,根据下一阶段应进入的电梯,将这一请求投入到下一电梯的请求队列中,实现请求的传递。最后在所有请求结束后通知输入线程结束所有进程。

在实现过程中主要遇到的问题为电梯进程和输入进程最终无法停下来,在经历漫长的调试后发现是上锁过多导致的问题。对调度器的方法类上锁过多使得进程之间相互陷入死锁的状态。

UML类图

 

协作图

Bug分析

这次作业主要bug是调度和分配,几种特殊情况下的电梯调度没有考虑清楚而导致一些错误的出现。

心得体会

通过本单元的学习我了解到了多线程的编程方式,在上锁方面主要使用的还是synchronized方法。对于多线程中遇到的各种奇怪的bug需要捋清调度思路然后对准错误进行修改。

posted @ 2022-05-03 10:37  tiderem  阅读(22)  评论(0编辑  收藏  举报