OO第二单元(电梯)单元总结
OO第一单元(求导)单元总结
这是我们OO课程的第二个单元,这个单元的主要目的是让我们熟悉理解和掌握多线程的思想和方法。这个单元以电梯为主题,从一开始的最简单的单部傻瓜调度(FAFS)电梯到最后的多部多线程智能调度(SS)电梯,我们需要掌握的多线程知识也从简单的线程间交互与同步到多种多线程模式相结合的复杂线程调度系统。
一、作业分析
第一次作业
第一次作业要求实现的是单部多线程傻瓜调度(FAFS)电梯的模拟。即一次接送一个人的VIP式电梯。

这个版本的作业其实不是我提交时所用的版本,而是我在提交之后第二次作业之前进行修改优化之后的版本。我第一次作业提交时的那个版本可谓非常粗糙,没有给输入单开线程,线程与线程之间的交互采用的也是轮询即sleep后再询问。总的来说我最开始的版本就是通过main来接受输入,再把输入存到一个用来保存请求的arraylist中,之后电梯从这个arraylist中读取请求,再自行进行处理。在第一次作业之后,我对第二次作业的内容进行了猜测与思考,决定在原有的基础上进行一些改进以方便第二次作业。我首先进行的改进是将线程交互的方式改为wait和notify,也就是实现一个输入与电梯之间的简单的生产者消费者模式,存放请求的arraylist就是托盘。对此我发现有必要将输入单开一个线程以充当生产者,于是就有了之后的改进。当然改进之后的作业也存在许多拓展上的问题,最为明显的就是我的电梯运行方法的编写是完全的面向过程的,没有丝毫考虑接下来扩展的事,是注定要在下次作业中重写的。其次就是没有编写调度器,指令时直接由输入传递给电梯的。
这次作业改进前的结构是只有main和电梯,改进后为简单的生产者-消费者模式。


这次作业的优点就是不容易出错,即使出错了也很容易追查出问题出在哪里。缺点也很明显,就是无论架构还是电梯运行算法的编写都极其不具有延展性,且后遗症会很多,虽然在之后进行了一定程度上的改进,但依然会给第二次作业造成不小的麻烦

程序出现的bug:由于此次作业比较简单,所以未出现bug
查找别人bug所用的策略:用一些比较边界的条件进行测试
第二次作业
第二次作业要求完成单部多线程可捎带调度(ALS)电梯的模拟

这次作业是我时间化的最多的一次作业,也是我完成最多工作的一次作业,完成了本系列作业的基础架构,为之后的第三次作业省下了不少力气。
这次作业相对上次作业我进行了极大的改进。通过与同学的交流与自己的思考,我初步定下了自己的架构。输入线程将输入传到总的请求队列里,调度器接受总请求并通过将其加入电梯的任务请求队列来将其调度给电梯以分配任务,电梯负责实现作业要求的算法。虽然这次作业中调度器只起到了从总请求队列将请求原封不动地搬到电梯的任务队列中,但考虑到第三次作业一定会有多部电梯所以我觉得还是十分有必要设计一个调度器。调度器的实现我采用观察者模式,把电梯定阅进调度器中,通过update函数将新的请求加入到电梯的任务队列之中。电梯实现的捎带算法的方法是,遍历任务队列,与电梯当前运行方向同向的上电梯请求加入到电梯的载客队列中,并将其从任务队列中删去。电梯每到一层都会检查载客队列与任务队列以上下乘客,电梯的目的地是所有载客请求中最远的,每次电梯搭载新的请求都会更新目的地楼层。当电梯达到目的地楼层后一次循环就算完成。线程的结束是电梯的任务队列中只剩下NULL请求且载客队列中没有请求。


这次作业的优点就是延展性很好,已经做好了下次拓展到多部电梯的准备。在电梯算法实现时我曾思考过是将指令在调度器中处理完毕后再传给电梯让它依次执行还是由电梯来实现捎带,调度器只负责分配任务,后来我考虑了多部电梯的情况,觉得如果让调度器来实现捎带会使得调度器类十分繁杂,因此我选择有电梯来处理算法实现捎带。在设计这个架构时,我极力减少了线程与线程之间的交互,以避免过于复杂的同步锁的情况出现,因为这样容易出现死锁,而死锁在debug时是十分难以发现和修复的。架构中电梯与调度器的交互只有订阅与更新。另一方面,之前留下的电梯的算法实现的问题也得到了改进,虽然没有实装一些电梯参数的初始化,但也设了相应的变量,为初始化参数做了准备。
当然缺点也是有的,由于我将电梯的整个捎带算法实现在一个方法中,因此不符合checkstyle(类行数过多),为解决问题我胡乱地将部分代码拆分出来形成新的方法,使代码可读性急剧下降。

作业出现的bug:一开始没有加载客队列因此出现了电梯造人的情况,即先下电梯再上电梯。
查别人bug采用的策略:自动生成数据进行debug
第三次作业
第三次作业要求实现的是多部多线程智能(SS)调度电梯的模拟

由于上次作业我做了许多工作因此这次作业对于我来说相对比较简单,我只需要实现调度和电梯的参数初始化。由于电梯多了规定的可达楼层,因此我选择在电梯类中创建一个int数组用来表示楼层是否可以停靠,即a[n] = 1就表示n楼可以停靠,0表示不可停靠。另外还在电梯类中实现了一个方法canReach用于检测传入楼层是否可到达。其余电梯初始化参数相对简单因此跳过不提。
调度算法主要实现了两部分功能,第一部分是指令的分配,将请求分配给任务最少的电梯,第二部分功能是请求的分解,即将一个电梯无法完成的请求分配给两部电梯(没有需要三部电梯才能完成的请求)。拆分出的指令分为前置指令和后置指令,后置指令必须在前置指令完成后才能执行,因此需要交互。但由于这两个指令时分配在两台不同的电梯之中的,本着减少线程间交互的原则不能通过简单两个电梯线程之间的交互实现指令的前后执行。因此我继承了给定的输入接口文件中的PersonRequest类来实现了一个新的变量flag和本类类型对象nextRequest用以交互前后指令。当指令为后置指令时flag置为0,其余指令flag置为1。前置指令的nextRequest为后置指令,其余指令的nextRequest为NULL。每当请求执行完成后都会执setNextFlag方法将后置指令的flag置为1,电梯执行算法时会在循环中忽略flag为0的请求。这样就在避免线程间交互的同时实现了前后指令的顺序执行。另一方面的分配则相对比较简单,就是统级电梯类中两个队列的size大小,将新指令分配给值较小的电梯。对于两类指令的区分,调度器会先检查电梯是否可以同时到达出发楼层和目的楼层,如果三台电梯中均没有能同时到达的电梯,则找到能到达出发楼层的电梯和能到达目的楼层的电梯中能共同到达的楼层已完成请求的分解。
电梯的算法依旧沿用上次作业的ALS算法,只不过加入了检查电梯人数是否超载的环节。


这次作业的优点就是我做的非常快(只花了一个下午),正确率也很好,我第一次体会到了做好架构能带来的好处。还有的优点就是由于线程之间的交互非常的少,因此同步非常的简单,不容易出现死锁。缺点也有,就是性能问题,我实现的ALS算法在急转向时会出现开两次门的情况从而导致电梯的效率比较低。

作业出现的bug:没出现bug
查别人bug采用的策略:自动生成数据进行debug
二、总结与感悟
这次我最大的感悟就是做一个延展性好的架构的重要性的好处。之前一直都是重构一时爽,次次重构次次爽,这次是真的真香了。由于我在第二次作业中完成了整个架构,因此我第三次作业的代码复用率极高,几乎是百分之百,且完成的也非常快。另一个令我感悟很深的事就是这次学到的这么多模式,无论是单例模式、生产者消费者模式、工厂模式还是观察者模式,单独列出来都不足以解决第三次作业的电梯问题,但是将他们结合起来就可以很好的解决问题,模式之间的组合是解决复杂多线程问题的一条捷径。
OO第二单元(电梯)单元总结的更多相关文章
- OO第二单元多线程电梯总结
OO第二单元多线程电梯总结 第一次作业 设计思路 Input为输入线程,负责不断读取请求并将读到的请求放入调度器中. Dispatcher为调度器,是Input线程和Elevator线程的共享对象,采 ...
- OO第二次单元总结——电梯多线程调度问题
OO第二次单元总结--电梯多线程调度问题 在这个单元OO学习中,我们终于迎来了期待已久(不是)的电梯多线程调度作业,开启了OO打怪之路的新关卡.虽然说经过了这三次作业,我对于多线程的理解还不能算是熟练 ...
- 电梯也能无为而治——oo第二单元作业总结
oo第二单元作业总结 一.设计策略与质量分析 第一次作业 设计策略 在第一次作业之前,我首先确定了生产者--消费者模式的大体架构,即由输入线程(可与主线程合并)充当生产者,电梯线程充当消费者,二者不直 ...
- OO第二单元——多线程(电梯)
OO第二单元--多线程(电梯) 综述 第二单元的三次联系作业都写电梯,要求逐步提高,对于多线程的掌握也进一步加深.本次作业全部都给出了输入输出文件,也就避免了正则表达式判断输入输出是否合法的问题. 第 ...
- OO第二单元总结(多线程的电梯调度)
经过第一单元作业的训练,在做第二单元的作业的时候,要更加的有条理.但是第二次作业多线程的运行,带来了更多的运行的不确定性.呈现出来就是程序会出现由于线程安全问题带来的不可复现的bug.本单元的作业也让 ...
- OO第二单元作业——魔鬼电梯
简介 本单元作业分为三次 第一次作业:第一次作业要实现单部简单电梯,停靠所有楼层,无载客容量,性能分考量电梯运行时间. 第二次作业: 第二次作业实现多部电梯,电梯数量由初始化设定,每部电梯都停靠所有楼 ...
- OO第二单元总结——电梯调度问题
一.设计策略. 在三次作业中,多线程程序的实现分以下几个步骤: 1. 主线程Main类的创建多个线程. 2. 共享对象的synchronized锁保证线程之间的互斥访问. 3. 采用notifyAll ...
- oo第二单元作业总结
oo第二单元博客总结 在第一单元求导结束后,迎来了第二单元的多线程电梯的问题,在本单元前两次作业中个人主要应用两个线程,采用“生产者-消费者”模式和共享数据变量的方式解决问题.在第三次作业中加入多个电 ...
- OO第二单元优化博客
OO第二单元优化博客 第五次作业没有性能分,但是,我在这一单元的宗旨就是写一个日常生活中 最常见的那种电梯,所以第五次我没有写傻瓜电梯,而是直接写了个\(look\),和第六次基本相同. 总计一下lo ...
随机推荐
- Linux防火墙开启关闭查询
1.centos7防火墙 命令含义: –zone #作用域 –add-port=80/tcp #添加端口,格式为:端口/通讯协议 –permanent #永久生效,没有此参数重启后失效 服务与端口的启 ...
- Python之PIL库的运用、GIF处理h
一.PIL库简介 PIL(Python Image Library)库是Python语言的第三方库,它支持图像存储.显示和处理,它能够处理几乎所有图片格式,可以完成对图像的缩放.剪裁.折叠以及像图片添 ...
- Python3源码学习-requests
源码:https://github.com/small99/AutoLink 本地安装包 version.txt记录版本号. 通过requests GET最新git上版本号. import codec ...
- java8_api_jdbc
jdbc-1 jdbc的概念 驱动的分类 连接oracle数据库 与任何表格数据源交互 代码编写步骤 加载驱动 Cla ...
- servlete基础
1. 使用servlet需要继承HttpServlet Servlet 生命周期 Servlet 生命周期可被定义为从创建直到毁灭的整个过程.以下是 Servlet 遵循的过程: Servlet 通 ...
- 19.3 Table 1-2.S3C2440A 289-Pin FBGA Pin Assignments (Sheet 4 of 9) (Continued)
应该为GPA22,这个在中文翻译手册里是正确的.
- 第三章 C#程序结构 (3.3 循环结构)
(1) while循环 当表达式为真,则执行下面的语句:语句执行完之后再判断表达式是否为真,如果为真,再次执行下面的语句:然后再判断表达式是否为真……就这样一直循环下去,直到表达式为假,跳出循环. [ ...
- MQTT研究之EMQ:【JAVA代码构建X509证书【续集】】
openssl创建私钥,获取公钥,创建证书都是比较简单的,就几个指令,很快就可以搞定,之所以说简单,是因为证书里面的基本参数配置不需要我们组装,只需要将命令行里面需要的几个参数配置进去即可.但是呢,用 ...
- Assets Library开发总结
Assets Library beta版的开发工作告一段落,本着有始有终的原则,这个项目还是需要做个总结的,恩~ 先甩一个链接:https://vimeo.com/238186671 考虑到该项目开发 ...
- kill -9 ,kill -12,kill -15
https://www.cnblogs.com/liuhouhou/p/5400540.html Linux kill -9 和 kill -15 的区别 大家对kill -9 肯定非常熟悉,在工作中 ...