OO第二单元作业总结

OO第二单元作业总结

第一次作业

(1)度量分析程序结构
UML类图:

方法复杂度分析:

类复杂度分析:

(2)程序bug

​ 这次作业的bug基本上是不熟悉多线程锁的基本操作,不知道锁什么,该怎么锁,notify也不会用,在运行的时候完全没有达到预期的效果,后来才知道锁要锁对象,等待和唤醒必须是对同一个对象上锁,否则等待的线程将不会被唤醒。

(3)总结

​ 第一次电梯作业目的是为了让我们了解并实现多线程,由于没有性能分的要求,所以我是按照傻瓜调度来写的,感觉这一次并不需要调度器,所以我这次作业就没写调度器,直接采用先来先服务原则,将新生成的指令放入请求队列中,每次电梯从请求队列中取一条指令,将这条指令执行完后再取下一条指令。对于线程安全性,我采用了BlockingQueue来存储请求,这样就不用自己来实现存取时的阻塞了。判断结束我是在输入时检测到输入结束就往队列里存一条从0层开始的指令,每当电梯里只剩这条指令时电梯就会跳出循环直接结束。

第二次作业

(1)度量分析程序结构
UML类图:

方法复杂度分析:

类复杂度分析:

​ 这次由于我一开始写的不是标准的ALS算法,之后为了向ALS算法靠拢一直在代码上打补丁,所以与主请求相关的方法复杂度很高。

(2)程序bug

​ 我一开始写的时候没有考虑到在电梯开门接人的时候,如果在开关门0.4s内这一层又来了人的情况,这样就会使本来能接的人没有接到降低了电梯的效率。在电梯内没有人的时候状态判断条件出错,导致能捎带的没有捎带以及部分情况下可能会下到-3楼以下或者16层以上。

(3)总结

​ 第二次作业是实现ALS调度的电梯,最初我是准备实现Look算法的电梯的,但经过自己构造了几组数据发现让ALS比Look快很多的数据很容易构造,为了求稳我就采用了ALS算法并保持ALS主请求的判断条件的基础上进行了优化。具体是在电梯内部没人但主请求存在时增加了同方向可捎带和反方向区间内可捎带。这次比起上次多了个调度器Scheduler,这个类用来存储请求队列并判断电梯是否可以上人,我并没有将调度器单独开一个线程,电梯每到一层就调用调度器中的方法来判断是否进人。由于这次要在队列里取特定的元素,所以就没有用BlockingQueue,这次就采用的是线程安全的Vector来储存请求。

第三次作业

(1)度量分析程序结构
UML类图:

方法复杂度分析:

类复杂度分析:

​ 由于这次我调度器一共11个请求队列,所以判断是哪一个请求队列时要写很多个判断语句,所以调度器里面很多方法复杂度很高。不同电梯运行楼层不同,所以判断电梯是否到顶加了很多判断条件。

(2)程序bug

​ 这次代码的bug有点多,因为我直接复用的上次的代码,上次请求队列又是static的,这就导致我11个请求队列其实是一个。在判断指令该加入哪个队列时我是将所有情况枚举出来再加,有些情况没考虑到就会导致这条指令没有加入任何队列。然后如果来了一个电梯执行不了的指令,我会将其拆分,由于2楼去3楼和4楼去3楼的指令没有特判,导致B电梯始终在2楼与4楼死循环,在电梯接到拆分指令时其他电梯会到特定层待机,但有些情况我没有将要去的楼层的标记清零且电梯状态没有设为STOP,导致我的电梯一直停不下来,导致强测WA了几个数据点。

(3)总结

​ 第三次作业加入了三部电梯且每个电梯可达楼层与运行速度均不相同,相比起前两次难度大了不少,为了更多地复用我上次的代码,我还是没有把调度器单独开一个线程,具体思路和上次类似,电梯每到一层楼就调用调度器里的方法判断是否进人,调度器里面存各个电梯的请求队列以及电梯间公共请求队列,为了使A电梯更高效运行我还把A的请求队列分成了上下两部分,这样就导致了我一共写了11个请求队列,所以调度器里面的方法长度几乎都是50几行。每个电梯独立运行,取指令时判断是否能送达目的楼层,如不能就把这条指令拆分,取出一条指令再加入一条指令,这样就保证了电梯里的指令一定会送到,另外,每次电梯拆分指令时都会让其他空闲电梯去指定楼层等待,减少电梯总共运行时间。在判断电梯是否结束时我是先判断如果输入结束,就存一条0层出发的指令到公共请求队列里,为了更有效运行,每个电梯优先选择自己队列里的请求,再选择公共队列请求,如果电梯访问到了起始楼层为0的指令且公共队列里只有这一条指令就设置isEnd为true,为了防止其他电梯中途拆分指令进队列导致本不该结束的电梯提前结束,我又在调度器里设置了一个静态变量count来记录处于等待状态的电梯数量,如果电梯此时没有指令可接且isEnd为true且count为2,就退出循环并将count值加一,这样就能使得电梯不会提前结束。当然,这次所有访问修改公共对象的属性的方法都加了synchronized来防止线程冲突。

​ 这次代码有很多多余的部分没有删(不敢删),比如我为了提高A电梯运行效率而将A分区,每当A将一个分区的请求送完才能换到下一个分区,为此我把原来8个队列扩充到了11个,加了很多代码,理想很美好但加了之后并没有实际的效果,后来发现我的电梯由于是ALS算法,在电梯为空时主请求会以先到先选的原则来,如果先来的指令是要跨分区的指令,那我A电梯就会直接运行这一条指令,而当前分区指令并没有执行完就换了分区,所以还是在写代码前要仔细斟酌,选一个好的算法,并在这个算法的基础上进行优化,不然就可能白费功夫。

发现别人bug策略

​ 首先我先将所有502条指令同时投放,用脚本来检测组内所有人的运行结果,如果有bug就针对性的找出bug的数据来测试,如果没bug就用自动生成数据脚本和检测结果脚本来进行自动化测试,这样效率高了很多。

Applying Creational Pattern

(1)生产者消费者模型

​ 这三次作业我都是用生产者消费者模型写的,输入线程作为生产者,电梯作为消费者,调度器作为托盘,由于调度器是被访问的,所以我没开调度器线程。

(2)单例模式

​ 由于三次作业中调度器是全局唯一的,所以调度器类只需要一个实例,定义为单例模式就可以使调度器的属性被其他进程共享,不会出错。在查看或修改调度器属性的时候直接锁调度器就行了,也十分方便。

posted @ 2019-04-23 23:45  cc17373432  阅读(114)  评论(0编辑  收藏  举报