OO2021 - 第二单元总结

2021面向对象设计与结构 - 第二单元(电梯)

序言

第二单元的作业可以说是经历了各种起起伏伏。

第一次作业由于对同步和锁没有足够的了解,因此使用了WaitQueue的方法来解题,加上轮询,导致CPU TLE的结果,未完成。

由于不想再有无效作业,于是我决定在第二次作业发布之前把同步块和锁的原理都了解清楚。这个决定对我之后的两次作业都有不小的帮助。由于了解了原理,加上写代码之前有思考代码结构,因此第二次作业代码写起来可以说是蛮顺利的。完成第二次作业也给了我更多的自信心去完成第三次作业。

 

同步块和锁的选择

第一次作业

第一次作业由于不了解同步块和锁的原理,因此我使用了WaitQueue的方式来尝试解题。

虽然未完成,但我认为代码中有几个代码是自己以后应该多留意的。

 

以下是Input模块里的run方法,这里外环使用了while(true),但我却忘了在输入结束后需要break掉,相信这也是导致CPU TLE的原因。因此以后使用这类while循环语句时要加倍注意。

第二次作业

第二次作业由于有了第一次作业的经验,解决了在输入结束后依然继续执行的bug。这一次作业使用了集中式调度,使用 synchronized同步块将waitQueue同步于所有电梯和输入间,让所有电梯在空闲时都可以自由抢占waitQueue里的乘客。

 

第三次作业

第三次作业由于出现了不同型号的电梯,导致第二次作业写的集中式调度出现了问题。因此决定改成全分布式,让所有电梯都拥有自己的等候队列,之后再使用调度算法将乘客分给电梯。

 

调度器设计

第一次作业为单电梯,因此没有特别设计调度器,而是使用了input模块将输入放入waitingQueue,再直接将waitingQueue传参给电梯模块。

第二次作业只是单纯的从单部电梯升级为多部电梯,因此代码可以说是第一次作业的微改版,只是使用了同步块将waitQueue同步于input模块和所有电梯间,让所有电梯自由抢乘客,同时避免不同电梯抢同一位乘客的情况。

第三次作业添加了不同型号的电梯,调度方式也从前两次作业的集中式改成了分布式。因此使用了一个简单的调度算法来调度乘客给各个电梯。

 

第三次作业架构设计的可扩展性

第三次作业的架构设计主要为输入,电梯,等候乘客队列类。

说实话这次作业的可扩展性并不好,因为代码是围绕着实现题目所要求的功能为主要目的来编写的,加上没有实现换乘,因此性能也不好。

这次的第三次作业由于个人因素导致时间紧迫,因此并没能在截至之前完成优化。电梯是收到一个乘客请求,就载一个人到目的地,这导致强侧全都RTLE了。

但已经想好优化方案,即让电梯等几秒,直到乘客累计到一定的量之后再开始载送。我写完这博客之后会继续努力尝试优化。

 

UML图

 

分析自己程序的bug

第一次作业

CPUTLE

这个bug到截至的时候依然找不到原因,之后发现原因就出在input模块的while语句在输入结束之后并没有break。这会导致输入结束之后,电梯退出了,input模块却还在等待输入。

 

第二次作业

乘客服务过快问题

指导书是说,开门或关门的0.2s期间乘客仍然可以进出,纸片人没有厚度。但我却忽略了开门和关门的时间顺序,代码写成了先过0.2s后才开门,再0.2s后关门。这个bug自己找的时候找不出问题,是问了朋友之后才知道的。

 

第三次作业

强侧RTLE

这个主要是因为电梯一开始使用了while循环语句和sleep的方式来等待输入,导致线程有可能一直霸占着waitQueue。这个问题在之后研究了wait和notify的用法之后就得以解决了。

 

心得体会

个人认为这一单元的作业难度整体比上一单元的作业好一些。

线程安全方面,经过了这三次的作业,深刻体会到了对一个对象进行同步加锁的重要性,像是第二次作业提交时就有出现过乘客还未到达,电梯就已经退出的情况。再来就是CPUTLE的原因,这让我对wait-notify方法有了更深入的理解,也了解到sleep并不是什么都可以解决的。

至于层次化方面,这三次的作业也能够感觉出来。在设计结构的时候就应该根据功能对对象进行分离,这可以确保代码有更好的扩展性。就像是第二次作业和第三次作业里,电梯其实基本上都是一样的,需要更改的只不过是调度器的调度策略罢了。有了层次化设计之后,重构的次数也确实少了。

posted @ 2021-04-25 03:19  tanchiachun  阅读(49)  评论(0编辑  收藏  举报