OO第二单元总结

                                             一.三次作业的设计策略

1.第一次作业的设计策略
在第一次作业中我设计了两个线程,电梯线程和输入线程,还有控制器模块作为连接两个线程的托盘。总的来说,我采用了生产者-消费者模式,其中生产者是输入线程,将输入的结果放入托盘中的waitingline队列,当电梯为空或到达某层时,电梯向控制器发出进入乘客的请求,waitingline队列选出在当前楼层的同方向的旅客(电梯不空)以及与电梯最近的楼层的旅客(电梯为空),并返回一个进入的乘客的ArrayList,加入到电梯中,同时给出电梯下一个周期的运行方向。

2.第二次作业的设计策略
第二次作业我是在第一次作业的基础上进行的迭代,与第一次作业的相同之处是:电梯线程基本没有变化,只是数量有所变化,输入线程也几乎没有变化。最大的不同之处在于我将第一次作业的控制器进行了重构,由于第一次作业对电梯和控制器之间分工理解的不是很透彻,导致控制器和电梯线程的耦合度较高,在第二次作业中,我将控制器和电梯线程的分工更加细化,例如在计算电梯运行的方向时,我在第一次作业中将direction作为电梯的内部变量,由控制器对其更改,而实际上,电梯的方向本来就应是控制器决定的,因此在第二次作业中我取消了电梯运行方向的内部变量,转由在需要获取方向时通过controller.getDirection()方法来实现。其次,在第二次作业中我将控制器分为了两级,低级控制器和电梯线程一一对应,当需要进入乘客时,将其所在楼层,方向,剩余载荷的信息发送给高级控制器,而由高级控制器分配乘客给低级控制器再给电梯线程。而waitingline队列也被我放置在了高级控制器中。

3.第三次作业的设计策略
第三次作业我相比于第二次作业更改的内容不是很大,整体架构没有区别,将旅客请求拆分的规则我采用了静态的拆分方法,既乘客刚进入等待队列时,就已经决定了它要上哪部电梯,在哪部电梯换乘,在几层换乘。为了实现这个过程,我采用了打表的方法,将出发楼层和到达楼层分为了九类,一一给出相互间道达所需要的路径。其他部分和第二次作业的差别不是很大,只是在电梯在某层接人时需要判断该人的目标电梯是不是当前电梯,若是则上。

二.第三次作业架构设计的可扩展性
第三次作业我的性能并不是很优,在强测中只获得了97分,在分析了自己的策略后,我发现我的性能不太好的原因主要是第三次作业我采用的静态拆分策略。例如当有某一乘客需要从16层到2层,三部电梯均在一层,由于静态拆分策略我采用了路程最短的设计,因此电梯A需要先到达16层接人,然后将其放在15层,此人在15层唤醒了电梯B,电梯B再上到15层接人,接上人后再前往2层,显然该策略要比将该人放在1层,再用电梯B将其从1层送往2层所需的时间多很多。此外,如果电梯的楼层数量再一次增加,我的表格可能会出现超过五百行的情况(现在为360行),也使扩展性不是很好。

三.基于度量来分析自己的结构程序

1.第一次作业



2.第二次作业



3.第三次作业






4.协作图(以第三次作业为例)

四.分析自己程序的bug
在三次的强测中,我都没有被发现bug,在第三次作业的互测阶段,我被一个特别的数据发现了一个bug。这个bug使我的程序的终止条件没有满足,最终所有的线程都进入了wait的死锁状态。在之后分析这个bug产生的原因时,我发现是我进入等待和唤醒部分的逻辑有问题。在wait()等待的条件时,我采用的是等待队列中没有符合该电梯的请求且该电梯的状态为false(false代表休眠,true代表运行)以及没有出现终止信号就一直处于wait状态,当有新乘客进入等待队列时,我通过更改所需要的电梯的状态(从false改为wait)从而使电梯唤醒,但我被发现bug的数据中,在最后时刻,同时有3人从一层进入队列,而有一个人的是从一层去往五层,其他两人是去八层和十四层,在静态的拆分中,去往五层的人同时满足B和C的要求,则将B作为主要求,当有空闲的B时优先用B接,无则用C接,但由于另外两人只能由B接,故B已经被唤醒,此时该人会唤醒电梯C,但由于B电梯的线程判断该人符合B的可到达楼层,会将此人抢先放入电梯B中,导致符合电梯C在waitingline中实际上已经不存在,故电梯C仍在wait状态,但其的status已经显示为了正在运行。由于我在判断结束是采用当最后一部电梯在进入休眠状态时判断其他电梯的状态(若均是休眠,则终止信号为true,所有的电梯从休眠状态唤醒。但由于电梯C的status一直为true且其不会再进入睡眠状态,故在运送完最后一名乘客后,所有的电梯线程都会进入wait的死锁状态。修改这个bug的方法也很简单,其实只用status信号就可以来判断电梯是否需要进入休眠,所以我将判断休眠循环的条件中等待队列中没有符合该电梯要求的人的条件删除,C电梯就可以被正常唤醒、再进入休眠状态时就可以将终止信号设置为true,使所有电梯线程能够正常结束。

五.发现别人程序(自己)bug所采用的策略
在发现别人程序的bug时,我是利用的自动评测机,由于方法比较枯燥不在这里赘述,在发现自己程序的bug时我采用的是在每个线程需要进入某个状态时print电梯号+进入某个方法。通过这样的方法,我找到了我第三次作业的bug。

六.心得体会
这三次作业让我真正的体会到了迭代的乐趣。在第一次作业中,一开始我的思路比较凌乱导致我绕了不少的弯路,到后来才认识到生产者-消费者模型的使用方法。由于第一次作业把电梯模块做的迭代性较好,在之后的两次作业中我几乎没有对电梯线程进行大的变化,主要是在调度的算法上面耗费的时间较多。我感觉直到第三次作业在互测被刀出bug时我才第一次的认识到了多线程中许多bug的特殊性。也希望这些经验能够在以后的实践中给我带来更多的帮助。

posted @ 2020-04-18 21:28  shmoo  阅读(150)  评论(0)    收藏  举报