第二单元总结

OO第二单元作业总结

1. 设计策略

1.1 第一次作业

一上来还不知道到多线程是什么的我就突然接触到了第一次作业,看完指导书后一脸茫然。于是我上网从0开始学习了多线程编程,这里给大家推荐一个java学习网站https://www.liaoxuefeng.com/wiki/1252599548343744,里面对java程序设计的教学非常全面且易懂。

第一次作业只有一个电梯,因此在线程安全上没有什么大的挑战,主要难度在调度算法上。

(1)程序框架上遵循了生产者—消费者模式,在缓冲区(在我的程序中命名为Manage类)设有addCommand和getCommand方法,用来添加和获取电梯命令,这两个方法都用synchronized关键字锁住,防止以后多电梯作业时出现线程安全的问题,增加扩展性,同时内部配有wait和notifyAll,具体逻辑不仔细赘述。

(2)第二单元有个主要的易错点就是如何判断电梯线程需要结束,第一次作业,本人在缓冲区维护了命令列表,并设置了breakMark属性用来与输入线程共享,判断输入是否结束。当命令列表为空,输入结束,且电梯内部没有乘客时电梯线程结束。

(3)调度算法本人没有仔细研究大佬们在讨论区提供的各种方法,而是选择了一个自创的方法,可能与大佬们的方法有相同之处。由于只有一个电梯,本人让Manage类完全控制了电梯线程,Manage类中本人设置了now和goal属性,分别代表电梯当前楼层和目标楼层,每次电梯与manage类交互时,判断当前楼层是否有上下乘客;当now=floor时,根据队列的上下乘客中楼层与当前楼层最近的位目标乘客调度电梯运行。电梯线程只负责上下楼以及维护一个在电梯内部的乘客的列表。

1.2 第二次作业

第二次作业增加了电梯的数量和能到达的楼层数,这在线程安全上给了我们很大的考验。

(1)由于第一次作业manage类只考虑了一个电梯,因此电梯的许多属性都设置在了manage中,方便交互。而本次作业有多个电梯,因此每个电梯的属性都需要自己来保存了,而manage类只提供电梯外乘客信息和电镀算法。因此我的第二次作业相较于第一次作业有较大的改变,相当于重构。

(2)由于每个电梯都是相同的,在搭载乘客上没有限制,在结束电梯线程的逻辑上也相同,因此本次结束电梯线程的算法和调度算法与第一次作业相同。

1.3 第三次作业

第三次作业相较于第二次限制了电梯的停靠楼层,这在调度算法上给了我们大的考验。

(1)电梯线程与manage类的交互方式相较于第二次作业没有较大的改变,依然是manage类维护电梯外乘客列表,并通过elevator类的now和goal属性调度;elevator类维护电梯内乘客列表,并根据now和goal上下运行。

(2)线程结束算法与第二次思路类似,不再赘述。

(3)在调度算法上,本人设计了两层调度,第一层负责在输入时解析指令,根据fromfloor和tofloor将指令分段,整个第一层调度算法维护在CommandAnalysis类中;第二层调度在Manage类中,负责维护两个列表,第一个为当前在电梯外的可执行指令,也就是第一段指令;第二个为不可执行指令,也就是第二段指令,只有第一段执行完后才能执行。第二层调度算法的整体思路不变,不同的是当第一段执行完后,根据乘客id寻找第二段指令,将其移到第一个列表中。

2. 可扩展性分析

2.1 功能扩展

本次作业我的程序功能可扩展性较高,只要不离开生产者—消费者模式和“电梯送人”的基本功能,任何功能都可以实现,因此功能扩展性不再赘述。

2.2 性能扩展

三次作业我的性能分都维持在97和98分左右,应该来说还可以。对于大佬们在讨论区分享的算法可能对于一些情况性能会明显降低,但对于一些情况性能极优。我的算法的特点是较为稳定,没有表现出极端的情况,对于所有测试点不是太优,但也不会没明显出现劣势。因此性能上本人自成了一套体系,可扩展性不大,如强行实现一些算法可能需要重构。

2.3 SOLID分析

SRP:电梯类仅含自身的类型、当前楼层等属性,以及自身上下人、移动的方法,调度器中也聚焦请求队列的操作以便和电梯交互,SRP 体现较好;

OCP:仅从功能上看OCP较好,但性能上较差;

LSP:第三次对于三种电梯,本人设计统一继承了Elevator类,子类完全实现了父类的方法,因此LSP较好。

ISP:三次作业均未设计接口操作,因此不再赘述。

DIP:在各个线程上属于并行状态,但主线程与第一层调度上存在调用关系,这里体现为DIP不太好。

3. 结构分析

因为三次作业在设计上存在很高层次的迭代关系,因此这里只针对最复杂的第三次作业进行结构分析。

1.1 UML图

1.2 复杂度分析

1.3 协作图

4. bug分析

第一次作业强侧出现了一个bug,是关于电梯线程结束的判断问题,初次设计是如果输入结束就像队列加入0楼操作,电梯线程读取到0楼操作时结束,这导致了一些情况下电梯线程无法结束的问题,出现了RUN_TIME_ERROR;在bug修复时舍弃了这种做法,而是增添breakMark属性,用于判断输入是否结束,输入与电梯线程共享访问这个属性。

第二与第三次作业强侧没有出现bug,但在中策阶段都提交了10次以上才通过。主要问题都是CPU_TIME_LIMITED_EXCEED,出现原因是电梯线程wait的条件判断错误,导致一些时候电梯得不到请求而产生轮询,使CPU过满。

总结以上的bug,原因还是对于多线程编程的理解不到位,导致在设计时考虑不周全,而在debug阶段手忙脚乱。

5. 总结感想

本单元的多线程编程看似较为复杂,但算法逻辑方面不如第一单元的多项式求导复杂,难度在于线程安全的控制,但只要逻辑清晰,还是可以克服的。

经过第二单元的学习,我对多线程编程产生了浓厚的兴趣,本单元也让我学到了单元测试、多线程调试等方法,对我的编程能力有了很大的提高,对我思想上的严密性也有很大的锻炼。

posted @ 2020-04-16 23:04  qsf  阅读(131)  评论(0编辑  收藏  举报