2021 OO第二单元总结

一 同步块的设置和锁的选择

  在这三次作业中,均采用的是synchronized()。在第一次作业中,由于当时并没有太弄懂如何去设置锁,用synchronized()将几乎整段代码给括起来,在Scheduler中,synchronized锁住Waitqueue(总的等待队列),在锁之中又锁Passengers(电梯的等待队列),在Elevator中与之相反,形成了交叉锁,这必然会导致死锁,当时并没有意识到这个问题,因此到了截止时间前最后一次提交直接全死锁。

  第二次作业痛定思痛,意识到了问题所在,第一次作业的逻辑十分混乱,因此在第二次中,选择了将调度器删掉,然后直接在InputThread中将人数平均分配至各个电梯,而电梯的线程里的大段同步块就没有进行修改。

  因为第三次作业中,Waitqueue不仅是有输入的数据,还有换乘的数据,第二次的方法不适用了,又将调度器改了回来,不过修改了锁的设置,只设置了一个锁,没有形成交叉锁。

二 调度器设计

     第一次作业的调度器没有实际的作用,在我的设计中,调度器其实做了电梯该去做的事情,应该放在电梯里,因此第一次的调度器虽然取名为调度器,实际上并没有用,反而让使得程序出现死锁的问题。

       因此,第二次作业中,由于实现的逻辑很简单,就将第一次作业中调度器的工作整合进了电梯,并删掉了调度器,而在InputThread中直接将PersonRequest分配到各个电梯的Passengers(电梯的等待队列)中,然后让电梯自己去接人送人。

       第三次作业中,第二次的方法不再适用,因为有换成,不能直达,因此电梯上下来的一部分乘客需要再次加入到总的等待队列中,重新分配至相应电梯的等待队列,因此又加入了调度器,调度器有一个总的等待队列,命名为allWaitqueue,输入线程得到的PersonRequest全部位与allWaitqueue,同时电梯运输的非直达的乘客,在下电梯后,更改起始楼层后加入到allWaitqueue,调度器的工作就是在allWaitqueue为空,没有后续输入以及电梯结束运输任务后,给每个电梯设置结束信号从而结束线程,然后结束自己的线程;在allWaitqueue为空但还有输入时,wait;在allWaitqueue不为空时,将PersonRequest按设计的逻辑加入到相应电梯的等待队列,然后唤醒电梯。

三 分析和总结第三次作业架构设计的可扩展性

类图:

UML协作图:

 

  在本次作业中,电梯的功能就是根据自身等待队列中的需求进行运送,调度器的任务之一就是分配PersonRequest给电梯,并设置要到的楼层(该楼层并非乘客的目的楼层而是电梯送该乘客到的楼层),因此,如果需求发生变化,如电梯的到达楼层,电梯的各种特性如速度,容量等发生改变,那么电梯几乎不需要做任何变动,电梯的拓展性还是较好的,但是发生这样的情况调度器就需要进行大量的改动了,不过也是不可避免的。总的来说,只要电梯的功能不发生太大的变化,程序的可扩展性还是比较好的,需求发生变化时,需要改动的几乎只有调度器和电梯的初始化。

四 分析自己程序的bug

       在第一次作业中,在第一部分也说到了,由于交叉锁的存在,导致测试点全WA,所以在设置锁的时候一定要小心谨慎,需要锁尽可能小且不能出现两个线程交替使用锁的情况。

       在第二次和第三次作业中,强测和互测均为出现bug。

五 分析发现别人程序bug采用的策略

       在发现别人的bug时,我尝试了去阅读别人的代码,看是否存在漏洞或者调度器设计不合理而导致电梯的闲置,但不幸的是,并没有因此找出房间内其他同学的bug,其次我也试图手动构造一部分比较极端的样例,同时也采用了之前强测的数据,但都未成功。

六 心得体会

  1. 先学好基础知识再上手,本单元第一次作业就是因为还不太理解多线程,就开始做,导致出现了死锁的问题,在调试的过程中,由于经验不足,也未能定位错误。
  2. 在保证正确的前提下才去考虑性能,不要为了优化去优化,一定要先保证自己程序的正确性,不能因为优化而导致出错。
  3. 打好提前量,OO一定不能留在周日做!
posted @ 2021-04-26 21:55  成泰吉  阅读(79)  评论(0)    收藏  举报