OO第二次课程总结分析
前几次的作业都是单线程的,总体来说和以前的思维模式和调试等存在着一定的挂钩,在设计上整体难度还不算太大,这次开始了多线程编程,难度可以说是质的飞跃,构思上所考虑的不止一点两点,在整体的基础上还要考虑线程的同步安全等问题,下面针对三次作业的分析来谈谈在多线程编程上所犯的错误和得到的收获。
一、多线程电梯
1.设计策略
作为多线程的第一次作业,又恰逢清明假期,可以有相对充足的时间来学习多线程的相关知识和进行构思(可以说这个清明假期过得非常揪心了),因为有了前面两次电梯的积累,这次关于同质和捎带的问题并未花太多时间(但是考虑前面的代码可塑性太差,这次就进行了重构,但核心思想没变),大部分时间用在了构思三部电梯的调度和安全问题上。多线程的设计与单线程不同,在构思实现逻辑的同时还要决定开多少个线程,每个线程之间的交互影响、线程安全问题等,复杂程度大大提升。在经历了多天的思考之后,我共设计6个线程(分别为主线程(Main)、输入线程(Inputhandler)、调度器线程(Scheduler)及三个电梯线程(Elevator))。共有4个请求队列(一个总的,3个各自电梯的)。
各个线程的工作如下:
- 主线程(1):其他线程的实例和启动
- 输入线程(1):在收到输入结束符之前持续接受控制台输入,将有效请求(其中无效和同质都不算有效)放入请求队列
- 调度器线程(1):当总的请求队列不为空或输入线程未结束时,不断扫描总的请求队列,根据三部电梯状态和分配原则来将请求分配给合适的电梯
- 电梯线程(3):当自己的请求队列不为空或调度器线程未结束时,不断扫描自己的请求队列,根据电梯状态和请求来执行相应的动作
关于线程同步控制的考虑,因为请求队列会涉及到加入请求、删除请求、从队列中取出请求及获取队列大小等操作,这都是线程不安全的,因此在对队列的操作上我都上了锁,同样,电梯状态会有改变和获取的操作,同样都加了锁。
2.程序结构分析
度量分析
类图
sequence diagram
个人觉得整体架构还算满意,各个线程分工较明确,只是在具体实现时有部分代码显得臃肿,还未能做到方法功能单一,部分方法用了太多的条件分支,在代码重用性方面有些欠缺,代码的可塑性不强。
3.bug分析
公测有四个样例没过,主要还是栽在了调度线程的问题上,分配请求的方法发生了错误,在判断电梯运动量上未做到安全,考虑不够周全,导致多个点爆了,另外时间永远是一个头疼的问题,公测终究还是被报了时间的错误。互测被找了一个格式错误,对格式边界的把握还是不够。
测他人时还是先从格式下手,再测一些基本功能的实现(先观察代码看必要的地方有无加锁,再针对性测试),然后从边界情况来找到是否符合预期,最后就是用大一点的数据去测。
二、IFTTT
1.设计策略
老实说,这次作业的难度比上次的要大,毕竟上次的作业有之前的作业的积累,并且给的时间相对较长,但这次作业不仅时间相对少,还涉及到文件系统,光是理解作业需求就花了挺长时间,导致最后作业完成的很糟糕。这次的构思基本就是针对一个作业开一个线程,每个线程监控每份作业相应的某个触发器和某个task,并且在创建线程的开始就为每个作业建一个状态快照,线程实时扫描文件,并实时生成更新快照,比较前后快照的不同看是否触发了相应的触发器,根据相应的触发器而做出相应的动作。各个线程如下:
- 主线程:处理输入,如队列,线程实例和启动
- Detail线程:处理detail这个任务
- Recover线程:处理recover这个任务
- Summary线程:处理summary这个任务
- TestThread线程:提供测试接口
- Watch(监控)线程:根据触发器不同让哪个任务执行
关于线程安全的考虑,对文件的操作会导致线程不安全,因此这块利用锁来实现同步,保证同一时刻只能有一个线程在对文件操作,避免应线程不安全而导致难以预料的错误。
2.程序结构分析
度量分析
类图
sequence diagram
这次的程序可以说写得很糟糕,由于时间的不足,没有考虑监控目录的情况,并且程序的主线程写了太多,显得很臃肿,应该将输入处理等移出,主线程只负责启动其他线程方为上策。同时,Safefile类忘记提供获取最后一次修改时间等方法。总之,这次的构思有些问题,程序结构设计的不是很合理。
3.bug分析
这次互测被找的bug是最多的一次,因为没有实现目录的监控,这部分被找了bug,同时,recover也未能实现,导致被测了许多bug,也是对自己的反思吧,毕竟自己没有实现那部分的功能。
这次互测就是针对几种触发器和几种任务的组合,一一进行几组测试,从而找出与预期结果相悖的点,针对找到的点,找到对应的代码,看关联的方法或其他,再针对地找其他bug。
三、出租车
1.设计策略
因为出租车是相互独立的,互不影响,故考虑每辆出租车一个线程,每辆出租车都有各自的私有属性,都能进行抢单、运送等动作,且出租车之间没有交互,各自独立。同时因为每辆出租车要从抢单出租车中选出合适的,故每个出租车都设了一个属于自己的请求队列,调度器负责为乘客选择合适的出租车,出租车负责将乘客送往目的地。因此,程序的线程如下:
- 主线程:读入地图信息、声明静态常量、线程实例及启动
- 输入线程:输入请求并将有效请求(无效、同质均不算)加入队列
- 出租车线程(100):出租车的各种运行(随机跑或按最短路径跑)
- 调度器线程:选出抢单出租车并进行派单
关于线程安全的考虑,本次总的请求队列是一个共享资源,故是非线程安全的,在对队列的操作中都加了锁,由因为调度时要获得出租车的状态、信用度即位置等,所以在出租车的状态、信用度及位置等的set,get方法上均加了锁。
2.程序结构分析
度量分析
类图
sequence diagram
这次程序的方法我尽量地去写得很短,只实现某一个功能,其他部分各人认为写得算是比较简洁,但调度器的run方法还是用了太多的循环和条件判断,导致度量变红,这一块应该改进,抢单可以另外用一个方法实现,而不用写在run里还有Taxi的判断走哪条路的方法复用性不够强,代码的相同地方过多,可以通过传目的地参数的方法进行此部分代码的复用。
3.bug分析
这次交得急,没有写测试接口,被报了一个设计缺陷,同时因为gui中算最短路径的方法耗时太长,在输出时我用的是假时间,但gui上跑得较慢,因为这个原因,接单和服务状态下车要比等待时跑的慢,被测试者找了bug,还有因为在遍历数组时条件判断不够充足,导致程序在一定间隔内输入的多条请求引发NULLpoint的crash。
这次找bug为了能保证出租车一定能接到单,我找的时候让出租车初始位置从某个点出发,便于进行测试。
最后的心得体会
经历过这最痛苦的三周,对多线程编程也有了自己的体会。在多线程电梯刚开始使用锁时,傻傻地锁住了sleep,导致线程之间不能并行,这个让我困惑了许久,后来逐渐缩小锁的方法的范围才解决。多线程的运行机制比单线程复杂得多,在动手之前要足够了解这种机制,不然真的发生了预料之外的后果你也会手足无措,所以事先设计构思、想好哪些资源需要共享,哪些需要同步,哪些线程是独立的,哪些是交互的,我认为这种考虑在多线程编程中是非常有必要的。
OO第二次课程总结分析的更多相关文章
- OO第四次课程总结分析
OO第四次课程总结分析 测试与正确性论证的效果差异及优缺点 测试,即使用测试样例来验证我们的程序是否能完成相应功能的过程.测试数据的产生基于前置条件和后置条件,通过执行测试数据检查方法输出是否满足需求 ...
- OO第三次课程总结分析
OO第三次课程总结分析 规格化设计发展历史 在网上找了好久也没找到合适的信息,稍稍参考了同学的博客.大致如下:最初的的软件并没有形式化方法,随着软件工程的兴起,为了便于工程间的协调管理,人们提出采用工 ...
- OO第二次博客作业——电梯调度
OO第二次博客作业——电梯调度 前言 最近三周,OO课程进入多线程学习阶段,主要通过三次电梯调度作业来学习.从单部电梯的傻瓜式调度到有性能要求的调度到多部电梯的调度,难度逐渐提升,对同学们的要求逐渐变 ...
- 电梯也能无为而治——oo第二单元作业总结
oo第二单元作业总结 一.设计策略与质量分析 第一次作业 设计策略 在第一次作业之前,我首先确定了生产者--消费者模式的大体架构,即由输入线程(可与主线程合并)充当生产者,电梯线程充当消费者,二者不直 ...
- OO第二次博客作业—17373247
OO第二次博客作业 零.写在前面 OO第二单元宣告结束,在这个单元里自己算是真正对面向对象编程产生了比较深刻的理解,也认识到了一个合理的架构为编程带来的极大的便利. (挂三次评测分数 看出得分接近等差 ...
- 【OO学习】OO第二单元作业总结
OO第二单元作业总结 在第二单元作业中,我们通过多线程的手段实现了电梯调度,前两次作业是单电梯调度,第三次作业是多电梯调度.这个单元中的性能分要求是完成所有请求的时间最短,因此在简单实现电梯调度的基础 ...
- OO第二次作业总结
OO~第二次作业总结 连续三周的电梯作业结束了,总的来说这三次作业做的还算平稳,既没有被刀,也没有刀中别人.那么接下来开始谈谈我对这三次作业的认识. 一.设计策略 我三次作业的设计思路基本上是相同的, ...
- OO第二单元小结
OO第二单元小结 一.三次作业代码分析. 1.第一次作业 第一次作业是单部电梯的傻瓜调度,由于其过分傻瓜,所以第一次作业我只有两个类,一个main,一个电梯,main类负责不断从输入流中读取命令,如果 ...
- OO第二单元多线程电梯总结
OO第二单元多线程电梯总结 第一次作业 设计思路 Input为输入线程,负责不断读取请求并将读到的请求放入调度器中. Dispatcher为调度器,是Input线程和Elevator线程的共享对象,采 ...
随机推荐
- MYSQL常用函数(时间和日期函数)Java中
CURDATE()或CURRENT_DATE() 返回当前的日期 CURTIME()或CURRENT_TIME() 返回当前的时间 DATE_ADD(date,INTERVAL int keyword ...
- Codeforces 1071 C - Triple Flips
C - Triple Flips 思路: 小范围暴力 大范围递归构造 构造方法: solve(l, r) 表示使l 到 r 区间全变为0的方法 为了使反转次数小于等于n/3 + 12 我们只需要保证每 ...
- mo系统常用语句
mo系统常用语句 一.总结 一句话总结: 1.语言:双语设置(繁体,英语)语句? {:chooseLanguage("確定要刪除么","Are you sure you ...
- ado.net介绍
System.Data:DataTable,DataSet,DataRow,DataColumn,DataRelation,Constraint System.Data.Common(各种数据访问类的 ...
- Python如何发布程序
https://blog.csdn.net/wem603947175/article/details/81589729
- English trip V1 - B 22. Here,There and Everywhere 无处不在 Teacher:Taylor Key: Be + Ving
In this lesson you will learn to describe what you see. 课上内容(Lesson) # How's the weather today? 今天的天 ...
- LeetCode--014--最长公共前缀(java)
编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...
- 20170906xlVBA_GetEMailFromDocument
Public Sub GetDataFromWord() AppSettings 'On Error GoTo ErrHandler Dim StartTime, UsedTime As Varian ...
- You Don't Know JS: this & Object Prototypes( 第3章 对象)
前2章探索了this绑定指向不同的对象需要函数引用的call-site. 但是什么是对象,为什么我们需要指向它们? 本章探索细节. Syntax the rules that describe ho ...
- 使用telnet模拟邮件的收发
smtp协议是一个简单的邮件传输协议,利用它我们可以将邮件发送给别人,这里将通过telnet这个程序利用smtp协议从网易向gmail发送一封邮件 基本步骤如下: 1.使用telnet连接smtp服务 ...