OO第二单元总结

前言

  又到了一个月一次的写博客环节,相比于上一个月,这一个月的OO作业完成的稍微顺利了一点,但随着学习的深入,其他科目的作业量加大,这门依然最硬的课也让我感到了不小的压力。这一单元的任务是多线程编程,以经典的电梯调度作业(据说已有五六年历史的北航传统作业)迭代极大地锻炼了我们的多线程编程和调试能力。以下是我的作业总结和心得体会。

第一次作业

  第一次作业的任务是编写一部可捎带请求(ALS)目的选层电梯。我采用了经典的生产消费者模式,以RequestInput线程为生产者读入PersonRequest类的请求并装入共享队列,OutRequest(电梯外请求队列)为共享队列,以Elevator线程作为消费者把请求拿出共享队列,线程安全方面用outRequest共享队列作为锁对象,采用同步代码块锁住对共享队列进行增删操作的代码。

  由于是第一周学习多线程,对很多概念理解不太透彻,我在这次作业中遇到了许多困难,险些自暴自弃,以至于在作业截止那天才刚刚过中测。当时出现的问题真可谓是“面面俱到”,从电梯逻辑到线程安全雨露均沾,真是不堪回首。Debug的时候还出现了“把一大块全加锁”的rz问题导致超时。还好经历了这几天的磨砺代码的架构没有什么问题,顺利通过了强测的所有测试点,也为下两次的作业奠定了良好的基础。相比于第一单元次次重构,第二单元的每一次作业都能够在原有架构的基础上做小手术,这也可谓是我面向对象编程的一大进步。

UML图

OO第二单元总结_第1张图片

复杂度分析

OO第二单元总结_第2张图片

 

 

第二次作业

   第二次作业相比于第一次作业添加了多部电梯的要求,其他部分都是和第一次相仿。这里我直接沿用第一次的架构,采用了比较简单的调度策略,即均分策略,轮流给每一部电梯调度任务,虽然算法比较傻瓜但也符合了课程所要求的时间规定。相比于第一次主要的改动难点在于结束条件的判断。而这次作业的强测和互测分别挂掉了两个点,都是因为有的电梯在收到结束信号之后并没有被唤醒,一直在wait没有退出,导致了超时。

UML图

OO第二单元总结_第3张图片

复杂度分析

OO第二单元总结_第4张图片

OO第二单元总结_第5张图片

第三次作业

  第三次作业添加了电梯可到达的楼层,换乘要求以及添加电梯的指令。还是沿用了第一次作业的架构,只不过改了一下调度方法而已,我的调度实现是在共享队列里的,改写PersonRequest类,添加了判断该请求是否可直达,运送的电梯ID,以及如果不可直达的话新生成的请求运送电梯ID,以及一些配套的成员方法。虽然运行的每一个电梯线程都能看见所有的指令,但是它们只会取出自己该运行的指令,而不会相互冲突。这种既定运行电梯ID的策略不具有很好的性能,但是逻辑清晰不易出错。

  在换乘设计方面,我才用了所有电梯在1层换乘的方式,性能较低,不会出错;换乘人到达1层的时候会向共享队列添加一个新的请求,由新的电梯来处理,从而实现换乘调度。

  当然在写代码中我出现了很多朋友也会出现的错误,那就是结束条件的判断。如果像前两次作业那样,电梯内外队列都为空而且读入了停止信号就关停该电梯线程,那么当有人在其他电梯里却需要换乘到该关停的电梯线程中时,就会因为没有电梯可作而出现"xxx not arrived"错误。为了解决这个错误,本人在调度器中维护一个ArrayList统计每个电梯需要运行的请求数量(这个数量里加上了二次转乘的请求),然后再类似生产消费者模式在这个队列里增减数字,把以前停止条件中的“外部队列为空”改为“该ArrayList中对应剩余请求数量为0”,有效而正确地结束了所有的电梯线程。在强侧和互测中,均没有出现任何错误。

UML图

OO第二单元总结_第6张图片

复杂度分析

OO第二单元总结_第7张图片

OO第二单元总结_第8张图片

由于没有重构,这三次作业标红的复杂度都同样集中在电梯调度和捎带方法中,其他调度方法复杂度良好。

总结

  总而言之,一个良好的架构真的对后面的扩展很有帮助。另外对于非大佬的同学而言,把更多的精力放在架构的合理以及线程的安全上而不是追求精妙的算法和更高的性能分上面往往是更明智的选择。这一单元的作业不仅提高了我的代码能力,也让我对面向对象有了更深刻的理解。

 

你可能感兴趣的:(OO第二单元总结)