ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

OO第二单元总结

2022-04-30 16:32:36  阅读:98  来源: 互联网

标签:OO 总结 请求 作业 电梯 线程 多线程 BUG 单元


一、程序架构分析

(一)、总体设计思路

第二单元的内容为多线程编程,具体任务为多个电梯的实时调度及交互。 在电梯调度方面,抽象出Strategy类,为每个Elevator对象都独立设置一个Strategy对象,用于确定电梯运行目标。具体实现,为每一部电梯设置一张工作表,表中每个元素为自定义的ListNode类,包含了乘客id,进出电梯状态,目标位置等信息,通过更改工作表,Strategy类即可控制Elevator运行。 为了较好地做到实时调度以及保证线程安全,在本单元中,程序的总体架构采用了“生产者——消费者”设计模式:封装InputHandler类处理输入,作为生产者发布各类请求;Elevator类作为消费者处理请求;两者之间通过共享对象WaitingTable进行交互。(实际上Elevator与WaitingTable间的交互是由其包含的Strategy对象完成的) 在同步块的设置方面,三次作业均选择在共享对象(WaitingTable)的方法上加锁,通过wait-notify方法完成线程间交互

(二)、逐次作业分析

1、第一次作业

(1)、架构思路分析

第一次作业利用“生产者-消费者”模式即可很好解决。但仍需要注重调度的设计与实现。 具体的架构便是按照总体思路中的描述进行的简单实现。

(2)、调度策略思路

第一次作业实现的调度策略基本为本单元打下了基础。 具体算法为维护一个任务表,任务表中的每个表项存储了目标楼层,乘客上下情况等(一个请求被拆分为两个表项),每次取得新请求时便更新任务表。该任务表总是满足如下性质:总是可以找到一个表项,在该表项及其之前的所有表项对应楼层构成的数列单调,如果该表项不是最后一个表项,那么在其之后的所有表项对应楼层构成的数列也单调。 当然任务表还应保证不超载、乘客先进后出等规则。

(3)、锁与线程交互

共享对象为WaitingTable,为其方法加锁,InputHandler调用其putRequest方法放入请求,Elevator中的Strategy调用getRequest获取请求,若尚无请求,则wait。 线程持续运行,直至输入结束且所有请求均被处理完毕。

(4)、UML图

image

2、第二次作业

(1)、架构思路分析

第二次作业新增了横向电梯和增加电梯请求,这就要求我们有效的管理各楼座、各楼层的电梯,均衡分配请求。因此,相比于第一次作业,第二次作业在架构上新增了ElevatorManager类用于添加电梯和管理请求分配。 此外,第二次作业将横向电梯和纵向电梯分开处理为VerticalElevator类和HorizonElevator类,横向请求和纵向请求也分开放于VerticalWaitingTable类和HorizonWaitingTable类中。 其余的架构基本保持不变。

(2)、调度策略思路

第二次作业的调度与第一次作业相比有两点变化:一是横向电梯的处理,而是同一楼座、楼层可能同时有多部电梯。 对于横向电梯,沿用之前的算法,A座到E座对应低楼层到高楼层。 对于同时有多部电梯的情况,采用轮流分配方式,当一个电梯线程想要获取请求时,由ElevatorManager给出一个分配id,若分配id与当前电梯id不匹配,则不分配请求,每分配一次请求,便更新一次分配id。

(3)、锁与线程交互

与第一次作业基本相同,横向和纵向互相分离。唯一不同是增加了ElevatorManager用于增加新电梯线程。

(4)、UML图

image

3、第三次作业

(1)架构思路分析

第三次作业变化为:自定义电梯参数、限制可达性、乘客请求无限制。 自定义参数简单即可实现,关键在于后两者。对于可达性的限制主要作用于请求分配方面,乘客请求的多样化则要求我们能够拆分请求,并且在线程交互中实现请求的发送。
为应对以上两点,在本次作业架构中,新封装Disassembler类,作用为将需要换乘的请求拆分为一组请求。同时,ElevatorManager类扩充出新的属性及方法,用于在一组请求的前后者间建立映射关系,实现实时请求发布。
同时,由于可达性的限制,导致请求必须分配到具体的某部电梯,否则会导致无意义唤醒,因此在本次作业中,候乘表为每个电梯都设置专属等待队列,不再使用统一队列。

(2)、调度策略思路

第三次作业总体沿用前两次策略。对于有多个换乘选择时,优先选择两个楼层间的换乘方案,否则随机选择,以避免某一换乘电梯负载过大。 对于可达性问题,会在请求分配时分配到具体电梯。

(3)、锁与线程交互

本次作业中的线程交互关键在于,电梯线程也有了发布请求的需求。我们通过在ElevatorManager中扩充相关的信号及映射表,使得电梯在完成一个请求后能够通过ElevatorManager发送后续的新请求。 同时,本次作业中线程运行结束的条件需要加上“没有尚未发布的后续请求”这一条件。且一个带有后续请求的电梯将一直运行直到后续请求发布。

(4)、UML图

image

(三)、UML协作图

在此展示第三次作业,即本单元迭代开发最终结果的UML协作图。
image

二、BUG分析

在本单元中,排除掉由于策略被卡的RTLE超时错误,测试中出现的BUG如下。
第一次作业:
BUG描述: 第一次作业中,对于乘客超载的判断逻辑不完善,导致超载。
修复方法: 每次更新策略任务表时都检查表中将要上电梯的人数与电梯中已有人数,若还有空位才更新任务表, 否则暂不更新。
反思: 该BUG属于低级BUG,导致原因在于自身对于设计逻辑思考的不完善。
第二次作业:
无BUG
第三次作业:
BUG描述: 由于可达性限制,若多个电梯共用一个等待队列,一个暂时无法被处理的请求会频繁唤醒无关电梯,直到可处理该请求的电梯将其处理。导致RTLE。
修复方法: 每个电梯独立拥有一个等待队列,每个请求在放入队列时就确定目标电梯,防止上述无意义唤醒行为。
反思: 该BUG较为隐蔽,属于多线程逻辑上的BUG。导致原因在于对多线程设计层次性的不重视,没有清晰明确各个线程的任务与交互关系。

三、HACK相关

本单元中,我并未进行过多Hack。主要的HACK方式为压力测试,使用有较多乘客,投放时间相近的数据进行HACK。
本单元的多线程BUG具有不可控性,若想做到稳定HACK,还需配合静态代码的阅读理解,需要较好的多线程思维能力。

四、心得体会

本单元带领我第一次接触到了多线程编程。下面分享个人通过本单元的学习,对于多线程编程几个关键点的体会:线程安全、线程交互以及层次化设计。
首先是线程安全,线程安全主要是要保证数据的正确性,防止多个线程对于共享对象数据的读写顺序混乱而导致错误。在本单元中,学习到了通过设置同步块和加锁的方法来解决这一问题。在实际作业时,个人主要使用设置同步块的方式,通过练习,能够有效保证线程操作的原子性,避免线程不安全的问题。
对于线程交互,在以“生产者-消费者”为代表的设计模式的指引下,通过本单元的练习,也有了一定的体会。在本单元中,线程间的交互以共享对象为抓手,通过“wait-notify”的方法完成交互。
最后,本单元的层次化设计也是一大考验。由于多线程的存在,使得增量开发更具挑战,一个需求的增加往往难以在一个线程中单独实现,需要多个线程以及共享对象的相互协作,这就要求我们有更加宏观统筹的视角来筹划我们的程序架构。个人认为,能否清晰划分线程功能,明确共享对象状态以及确定线程工作流程,是架构层次化设计良好与否的关键。
多线程是计算机程序中重要的一环,是实际软件中的关键技术,但我以往少有接触,只是在各类理论课上听闻过,因此,对我来说,本单元确实是一个不小的挑战。首先是第一次接触多线程编程,编码时很多细节不理解、不熟练,其次多线程调试不易,而且会有很多以往未曾遇见过的BUG。不过经过本单元训练,基本上对于简单的多线程编程也有了较强的处理能力。
本单元带我走入了多线程编程的大门,同时也锻炼了我的编码能力和架构设计能力,可以说是一次十分宝贵的学习经历。

标签:OO,总结,请求,作业,电梯,线程,多线程,BUG,单元
来源: https://www.cnblogs.com/ydy2001/p/16210523.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有