OO第二单元总结

  第二单元的作业主要是围绕线程的协同和控制方面训练,依托的对象主体是电梯。难度也是由第一次的一个电梯的一次一人的调度策略到最后一次的三部电梯的调度,并且还会涉及到换乘的问题。

一.第一次作业

  第一次作业需要完成的任务是单部多线程傻瓜(FAFS)调度电梯的模拟。我设计的思路主要是参照了ppt上的做法,将调度器作为一个对象,电梯和请求输入作为线程,然后将调度器作为参数传入到电梯和请求输入的线程中。在请求输入中,就是仿照输入接口文档中的demo写的一个循环,将输入的请求都存储在调度器的一个ArrayList队列中,在输入结束的时候会告知调度器对象,调度器对象将结束信号传给电梯线程结束运行。调度器更多的是作为一个乘客请求的容器,主要的调度工作还是在电梯线程进行,按照请求的顺序一个一个的送到目的地,在乘客进入电梯的时候便将其从请求队列中删除。总体来说是十分耗时的,并且在电梯线程的主程序的设计时采用了轮循,浪费CPU时间,在之后的两次作业中采用了wait()和notifyall()去避免了轮循。在线程的安全方面,主要是对调度器这一对象加锁,在对乘客请求队列进行删除、插入、调用的时候都会加锁,去保持数据的同步。下面是整个程序的类图。

  PersonInput就是处理乘客请求输入的线程,Scheduler是调度器对象,其中的personRequests就是请求队列,Elevator是电梯的线程,MainClass是主类,程序的入口。请求输入线程和电梯线程都是从MainCLass中start,结束后回到MainClass中。OO度量如下图所示:

  从图中可以看到整个程序的基本复杂度、软件模块设计复杂度以及结构复杂度都没有超过正常值,便于模块化以及维护。所以在设计上还是比较简单的。线程

  整个程序的bug就是在刚开始输入的时候从0.0时间输入会出现问题,我当时的解决方法是将时间的初始化放在了最后,将不能把时间的初始化放在最后这一条忘记了,但是之后的话也没出现什么问题,便没有去修改代码了。在强测中出现了一个错误,全部的数据都在0时刻输入的时候出现了问题,我在电梯运行前sleep100ms将全部的数据读入,便解决了这个问题。

 第一次作业的优点的话可能就是整个程序的架构比较简单,缺点的话就是调度算法比较简单,比较耗时。

二.第二次作业

  第二次作业是在第一次作业的基础上,将先来先服务(FAFS)的调度算法换成了可稍带调度(ALS)算法。整个程序的设计上还是和第一个作业是一样的,调度器对象,线程和请求输入线程。不同的是在电梯线程中,多了一个已经上电梯的人的队列,在运行过程中,到每一楼层就去判断是否还有人能进入电梯,并且总是以电梯中目的楼层离目前楼层最近的为目标楼层,这样就实现了ALS算法的调度。在这次作业中限制了CPU时间,所以便抛弃了第一次作业中的轮循,使用wait和notifyall去控制线程的运行,并且将时间的初始化放在了程序的开头。整个程序的类图如下图:

  与第一次作业基本是一样的,在Elevator中加入了personOnEle队列去存储在电梯上的人。请求输入线程和电梯线程都是从MainClass中start,结束后回到MainClass中。整个程序的度量如下图所示:

  可以看到三个度量大部分都是在正常值范围内,只有少部分超过了正常值,尤其是ELevator.eleRun()方法,耦合度比较高,主要原因是两种情况的代码相似度很高,所以代码质量也比较低。之后的设计一定要避免重复代码的出现。

  这次在弱测环节环节并没有出现bug,但是在强测中出现了比较大的问题,发现在所有的错误中有些人是会在同一层上两次电梯,主要是在对请求队列没有做到同步,上一个做了删除请求操作,但是在下一重循环的队列副本中还是存在这个请求,所以便会出现上两次的情况。但是在第二次作业分数出来之后,我一直以为是锁加错了地方,所以便没有进行仔细的思考,导致在第三次作业中依然使用了这个方法,导致第三次作业全军覆灭。所以还是给了我一个很大的教训。再仔细思考一下的话,这其实是调度算法的设计问题,在到达每一个楼层之后,判断是否有乘客可以搭乘便可以了,但是我在电梯要关门的时候还判断一次是否有乘客需要搭乘,这一操作是完全没有必要的,而且是十分傻的设计,导致自己第二次和第三次的作业得分很低,希望自己在以后的设计中吸取这次的教训吧。

  这一次作业的优点实在想不出来,缺点就是存在调度算法的致命bug没有发现。

三.第三次作业

  第三次作业是多部多线程智能调度(SS)电梯的实现。有三部电梯,并且这三部电梯的停靠楼层都不尽相同,所以会存在换乘问题。这次作业我采用的是课堂上提到的Work Thread模式,但是也不尽相同。采用了两级调度机制,第一级调度是将请求队列分给对应的电梯,第二级调度和第二次作业的调度是相同的作用,采用的是可稍带(ALS)调度。在第一级的调度中,将请求分给等待队列人数最少的并且满足条件的电梯。对于那些需要换乘的请求,首先是选择换乘电梯以及换乘的楼层,我采取的办法是选择离初始楼层最近的两个电梯都可以停靠的楼层,将一个请求分成两个,然后将该第一个请求分给乘坐的第一个电梯,当执行完毕后,将第二个请求请求写回一级调度器的请求队列中,在去选择电梯乘坐。整个电梯的类图如下所示:

  ClientThread是请求输入的线程,Channel是一级调度器线程,SecondChanne是二级调度器,ElevatorThread就是电梯的线程,MainClass是主类,程序的入口。Channel和ClientThread线程是从MainClass中start,ElevatorThread线程都是在Channel中start。程序的度量如下图:

  整个程序大部分还是都在标准值内的,ElevatorThread.eleRun()和Channel.chooseFirst()的耦合度比较高,主要原因是在方法中不同条件的代码的相似度比较高。并且在Channel.chooseFisrt中使用了很多的if语句,导致代码在后期确实有点难以维护。

  在过中测的时候,出现的问题是线程停止条件的问题,最后我的设计是在全部队列都为空并且输入停止时将由Channel一级调度器给关闭所有电梯线程。关于这次的bug分析在第二次作业中已经提到了原因,给了我很惨重的教训。在之后自己进行测试的时候应该想清楚所有的情况进行代码的测试。这次作业以及第二次作业的bug我都做了修改。

  这次的代码优点想不出来,缺点还是有致命的bug。

四.心得体会

  经过三次电梯的作业,对有线程程序的架构以及线程安全机制有了更好的认识。并且意识到自己测试程序这一环节的重要性,不能以通过中测为终止,应该把所有的情况都想完才能去提交。

转载于:https://www.cnblogs.com/lzd1998/p/10763081.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值