概述
OO第二单元的作业主要是多线程的学习和使用。第一次作业只有一个傻瓜电梯,第二次作业是带捎带的电梯,而最后一次作业是三部带优化与特定条件的电梯,作业的实现难度也越来越大。
第一次作业
设计策略**
第一次作业简单的采用消费者生产者模型,使用电梯和输入两个线程,获取请求时对请求队列加锁加锁。电梯完成一个请求后从请求队列中取出一个请求。队列为空但输入线程未结束时就等待输入线程再次输入;直到输入线程结束并且所有人都到达了目的楼层之后就结束。
复杂度分析
类图
度量分析
elevator中的run()
方法因为承担着电梯的运行与交互任务,所以iv(G)和整体的v(G)偏高;电梯由于是傻瓜电梯,没有一定的优化调度策略;电梯的运行判断都集中在了该类导致该类的循环复杂度过高。导致OCavg和WMC偏高。
1.3 UML协作图
第二次作业
设计策略**
电梯不断的与调度器进行交互来而更新策略,进行人员的捎带。根据规定的捎带原则进行对人员的捎带,电梯在无请求时进入wait状态,有新请求入队时将其唤醒并采用特定的规则进行捎带。run()方法与其他方法的紧密程度很高,在这个方法中也使用调度器对电梯运行方向的其余楼层进行遍历,判断电梯是否需要转向,从而避免遍历判断的。
复杂度分析
类图
度量分析
UML协作图
第三次作业
设计策略**
由于加入了换乘操作,使用了一个主调度器和三个子调度器,主调度器接受请求并分发任务给三个子调度器。子调度器进行电梯的调度。当有换乘请求出现时,主调度器决定换乘楼层并将任务下发给子调度器,子调度器在完成换乘的第一部分后,将第二部分的换乘作为一个新的请求发给主调度器,再由主调度器进行任务的下发;电梯的结束条件是同时对所有电梯的请求队列以及输入线程进行判断。输入线程结束时以及其他电梯线程结束时,都需要将等待的电梯线程唤醒,防止电梯无法唤醒。
复杂度分析**
类图
度量分析
UML协作图
SOILD原则分析
在本单元作业中,完全不太知道有SOILD原则,在作业中也没有很好的去运用。对于SRP-单一功能原则,对于电梯类和调度器类,影响电梯类的是电梯的运行方式,影响调度器类的是调度器的调度方式。而对于OCP-开闭原则,从第一次到第三次作业,调度器只是增加相应的调度策略,电梯运行没有很好的遵从这一原则,三次电梯线程主要是对run方法的重写。LSP-里式替换原则,ISP-接口隔离原则以及DIP-依赖反转原则由于我的作业中几乎没有继承接口。很难直接分析。
BUG分析
bug主要是细节问题,第一次作业把电梯的运行楼层范围写错了,导致有些楼层到不了;第二次作业循环条件的考虑不周导致只能进行前几次捎带,而往后面的捎带就不能进行了,因此对于细节问题的处理能力必须加强。 由于我不会写自动化测试,对于hack别人主要是从增大相同捎带请求的数目来看cpu的运行时间是否超时和程序对于ctrl D的处理能否正确同时保证线程安全。
体会
我学习并了解了多线程的知识,首先是对锁的理解,虽然每次作业都使用了锁,但也没有十分深究锁的必要性与安全性,导致了锁的滥用,不仅降低程序的效率,而且会导致线程不安全,程序会出错误,在本单元作业中,我慢慢基本具备了一定的保护线程安全的观念。以及对wait()和notify方法的使用和区别分析有了一定认识。同时也认识到多线程的调试比较困难,多线程出现的bug难以通过有效的方法使得其复现,需要编写自动化测试测试,而这也是我目前的水平所十分欠缺的地方,此外代码架构都比较乱,几乎没有什么可扩展性。