其他分享
首页 > 其他分享> > OO第二单元总结

OO第二单元总结

作者:互联网

OO第二单元总结

作业架构及分析

hw5

基本要求

A-E五栋楼,每栋楼里一部电梯,实现电梯调度模拟。

基本设计(架构&策略&同步块&调度器)

本次作业由于之前没有接触过多线程编程,我小心翼翼地参(照)考(抄)了实验架构。采用生产者-消费者模式,构建ReQQ类作为“托盘”作为共享对象,分别在:

(1)总调度器中实例化为allReQQ,用于存储未被投喂至电梯的请求。
(2)每部电梯中实例化为processReQQ,用于存储该楼座中的所有请求。

(1)输入线程InputThread官方包已经实现阻塞,不需要wait,而结束条件为读取null时跳出while(true)即可。而其他线程的结束的必要条件均含输入已经结束,故需要在共享对象ReQQ中设置isEnd标记外部输入是否已经结束。

(2)调度器中只需要其内部存储请求的队列为空时wait即可,具体实现为ReQQ共享类的getOneRe方法设置wait。结束方面即为队列为空且输入未结束即isEnd==True。

(3)电梯不需要运行时需要wait, 或者其实sleep(50)也行, 即其内部请求队列为空即需要wait。在实验架构上这个wait是唯一需要自己新增实现的。具体方法为在共享对象ReQQ中专门设置判断电梯是否需要wait或需要结束电梯线程的方法judgeWait()作为while(true)中true的替代。检测到输入结束且电梯无请求时结束线程;否则若电梯内无请求则电梯进入wait()。

    public void run() {
        boolean isUpping = true;
        while (buildingReQQ.judgeMove()) {
            isUpping = decideMove(isUpping);
            isUpping = decideAction(isUpping);
        }
    }

电梯所在座的请求队列为BuildingReQQ,通过布尔型isupping记录目前电梯“试图”上下行的方向。decideMove()函数判断电梯是否要上下行及做出移动行为,并更新isUpping。decideAction()函数判断电梯是否要对当前层开关门,并更新电梯的isUpping。

UML类图

hw5类图

UML时序图

hw5类图

hw6

基本要求

基本设计(架构&策略&同步块&调度器)

UML类图

hw5类图

UML时序图

hw5类图

hw7

基本要求

基本设计(架构&策略&同步块&调度器)

UML类图

hw5类图

UML时序图

hw5类图

复杂度分析

这单元其实没太注意复杂度的事,甚至电梯的look实现算法还写了60行多一点被我压到60行......简单列举hw7复杂度如下表:

只取复杂度最高的几个方法,很显然都是实现look调度策略的方法:

方法 基本复杂度ev(G) 模块设计复杂度iv(G) 模块判定结构复杂度v(G)
NormalElevator.decideMove(boolean) 10.0 18.0 20.0
LoopElevator.decideAction() 4.0 18.0 19.0
NormalElevator.decideAction(boolean) 3.0 25.0 26.0
NormalElevator.judgeDirection(boolean, ArrayList) 14.0 12.0 18.0
LoopElevator.decideMove(boolean) 14.0 20.0 24.0
所有方法平均值 1.78 2.76 3.26

其它方法的复杂度都不大。可见实际上实现电梯调度的函数应该被我拆的更碎一些 (好像我根本没有面向对象思维......)
另外感慨:方法数足够多,方法平均复杂度就可以非常低~

类复杂度一一列举如下:

类名称 平均圈复杂度 最大圈复杂度 总圈复杂度
AddElevatorReQQ 1.5 3.0 9.0
AddElevatorThread 2.0 3.0 6.0
EndCounter 1.4 3.0 7.0
ExtendPersonRe 1.0 1.0 12.0
InputThread 3.0 5.0 6.0
LoopElevator 3.5 18.0 57.0
LoopElevatorTable 1.2 2.0 6.0
LoopElevatorTable.Information 1.0 1.0 4.0
Main 3.0 3.0 3.0
MoveReQQ 1.5 5.0 21.0
MoveScheduler 4.3 7.0 13.0
NormalElevator 4.5 14.0 50.0
OutputThread 1.0 1.0 3.0
平均值 2.32 5.08 15.15

调度器的平均圈复杂度主要是方法数过少所致的,而两个电梯类的复杂度主要是其调度算法函数所致的。

Bug&Hack分析

Bug分析

这一单元的作业在公测调试时先后发现了很多Bug和性能问题,列举如下(首先在这里鸣谢臻哥、吕哥的带带):

hw5

hw6

hw7

而在强测和互测中均未出现正确性Bug,三次的得分别为98.8、98.9、98.4。

前两次性能没有最大化的原因可能有:没有做量子电梯常量级别优化,进人放在开门后导致中间0.4s新来的人接不到,函数写的复杂度过大,每次运行程序损失了少量时间、hw6遍历共享对象暴力加锁保证了安全性却牺牲了性能等等。第三次作业除了前面的部分问题外主要还存在换乘策略的问题 ,毕竟眼见dl同学天秀最短路算法

Hack分析

与第一单元不同的是,这一单元测试数据手搭极其困难且效率也很低,另外许多问题多次测试才能复现或者更加隐蔽,更加需要覆盖式的轰炸才能显现。总之就是——有评测机会好的多,或者需要有时间和耐心阅读他人代码。

hw5没想到会重测,hack到容易hack中的数据就摆了,最后重测了,然后一刀也没中......

hw6、7各成功hack2人,一次隐蔽的线程不安全问题ConcurrentModificationException、一次输出时间戳非递增、一次CTLE轮询、一次电梯反复到达本层问题。

(所以可能边界压力数据其实很适合自测和互测,尤其是hw7课下有某位dl同学构造了add所有可能的电梯,然后同时间投入所有可能出现的移动请求两次的上万条数据。测完发现不会轮询、能通过同学写的正确性检查程序安全感直接拉满。)

(救命每天被ddl追着杀 课太多了 真的没时间读代码啊)

心得体会

多线程编程需要耐心,码量可能相对小一点,但细节非常多,需要仔细考虑到所有情况,并在大多数时候进行颅内debug。线程交互、线程安全都是全新的概念,需要掌握。此外设计模式的魅力在这单元开始展现,生产者-消费者模式的代码编写重难点个人认为在共享对象的选取、设计上,实验架构的生产者-消费者模式和其共享对象设计伴随了我整个单元。

另外,多看讨论区,多和身边dl请教代码思路、设计技巧等等十分重要。还有意外的一点是面向对象的思维有了一点点进步(一点点)

最后,通过廖雪峰的教程等等,我认识到这一单元只是多线程的冰山一角,而具体在实现中我甚至一个lock锁都没使用过,全都使用了synchronized,更遑论各种各样类别的锁。长路漫漫,总是越学习便越感到自己的渺小。

标签:OO,总结,请求,复杂度,调度,电梯,线程,单元,wait
来源: https://www.cnblogs.com/Ncikwz-20231190/p/16220170.html