OO第二单元总结

第五次做业

本次做业,须要完成的任务为单部多线程傻瓜调度(FAFS)电梯的模拟。算法

设计策略

先来先服务的单电梯是一个标准的"生产者-消费者"模型。虽然在本次做业中调度器彷佛是没必要要的,但为了更好地应用"生产者-消费者"模型,并方便下一次做业的扩展,仍是应该保留了调度器的概念,将其做为"托盘"来存放还未服务的请求。编程

显然,读取输入并解析为请求就成为了生产者,而电梯就成为了消费者,而在本次做业中调度器其实只起到了存放共享数据的做用,并无作任何真正意义上的调度。生产者将请求推入位于调度器里的请求队列里,另外一边电梯按照先来先服务的傻瓜调度算法将请求一个个取出来并执行。为了保证访问请求队列的线程安全性,推入和取出请求的方法必须用synchronized关键字上锁。设计模式

输入和电梯各是一个线程。当请求队列为空时,电梯wait(),直到一个新的请求被推入请求队列,电梯被唤醒。安全

程序结构

本次做业结构比较简单,一共四个类:输入、调度器、电梯和主类。输入和电梯两个线程经过调度器中共享数据的方式进行通讯。多线程

在度量上能够看出总体比较均衡,没有出现个别方法复杂度过大的状况。架构

关于BUG

记得应该是一遍过了,没有发现本身程序的bug。性能

菜鸡如我也不会测别人的bug,互测摸了。测试

第六次做业

本次做业,须要完成的任务为单部多线程可捎带调度(ALS)电梯的模拟。优化

设计策略

此次的电梯依然只有一个,但要求支持捎带。要实现捎带,就涉及到主请求捎带请求这两个概念。当电梯处于空闲状态时,尝试从请求队列中取出一个请求,做为主请求。在该请求被完成以前,电梯运行路径上遇到的全部目标方向与电梯运行方向相同的请求均被做为捎带请求,存入位于调度器中的捎带请求队列中。当主请求被完成后,从捎带请求队列中取出一个请求,成为新的主请求。编码

以上取请求的操做依然遵循先来先服务的原则,但有了捎带功能后,某些请求能够被顺带提早知足,电梯的运送效率获得了极大的提高。

设计模式上仍然采用"生产者-消费者"的基本模型,但此次调度器有了些实际做用,用于管理主请求和捎带请求之间的转换关系。

程序结构

因为仍然是单电梯,仅仅是增长了捎带功能,而模型没有变,因此程序结构大致上和上一次相似。

此次代码写得比较急,有些该封装的地方没封装,该复用的地方没复用,因此致使某些方法比较冗长。好比电梯线程的run()方法中,将细节都暴露了出来,有很多重复的语句,如今我本身理解起来都有些吃力。有时间仍是应该把代码风格优化一下。

关于BUG

完全崩盘。要怪只能怪没有作好足够的本地测试(其实也不会测),结果公测和互测都爆炸了,而缘由仅仅是从-1层到1层有个地方忘了处理。就由于这一个小细节,整个做业的努力白费,算是一个很大的教训了。下次不能再这么佛系地对待测试,也毫不能对本身的程序抱有莫名的自信。

第七次做业

本次做业,须要完成的任务为多部多线程智能(SS)调度电梯的模拟。

设计策略

终于来了,传说中OO做业的难度峰值。

相比前两次,最主要的区别就是由单电梯变成了多电梯,那么如何处理三个电梯之间的协做关系就成了主要问题。而事实上,所谓的协做关系也只是保证线程安全性,在这个基础上采用电梯间相互争抢的模式,即谁先到达某个请求的出发楼层,谁就服务这个请求。这种策略简单暴力,调度器不须要分配请求,而效率最后被证实也很好。

在电梯调度算法方面,我采用了LOOK算法,并进行了必定的优化:电梯每达到一层,检查请求队列中是否有能够知足的请求,若无则wait(),如有则根据如今电梯内是否有人分两种状况移动:

  1. 电梯内有人,保持原来的运行方向,由下至上再由上至下循环扫描全部能到达的楼层;
  2. 电梯内没人,若当前方向上没有能够知足的请求,则调转方向,不然保持原方向移动。

经过使用wait()和notifyAll(),电梯在空闲时不会无脑疯狂调转方向,从而更贴近真实状况。

此外,本次做业对电梯增长了更多的限制条件,如轿厢容量、可停靠楼层等。对于单个电梯没法知足的请求,须要由调度器将其拆分红两个请求,而后先把第一个请求放进请求队列。这里我利用了HashMap结构,将第一个请求做为键,第二个请求做为值存储起来。每当一个请求被完成后,就在HashMap中查找是否有对应的第二个请求,如有就放进请求队列中。

程序结构

本次做业新增了Request类和Floor类。Request继承了PersonRequest,以实现请求的拆分从新建立,并加入状态位status,用来标记某个请求当前正处于未被服务的状态,仍是已经在某个电梯内部了。Floor做为电梯的构造参数之一,做用是管理电梯的楼层信息,包括可达楼层、最高最低层、判断某个楼层是否可达。包括Floor在内的全部电梯属性均可以在主类中显式地修改,避免硬编码,下降耦合度。

我在最后一遍提交前已经把整个程序结构优化了一遍,封装了不少过程,让方法长度尽量的均衡,然而如今看来貌似仍是有些差强人意。这个方面还得再下功夫……

关于BUG

此次我深入吸收了上次的教训,不会测bug就虚心请教大佬,要来了评测姬。正所谓不测不知道,一测吓一跳。结果果真显示有严重的bug,一个是拆分请求后第二个请求推入时间过早,致使乘客还没从第一个电梯出来就进了第二个电梯;另外一个问题是某些状况下电梯wait()后就再也醒不过来了,缘由在于notifyAll()的逻辑不太对。

多线程debug的确比较难受,不过好在我向来就习惯用print大法,在每一个转向、睡眠、唤醒等关键环节都print出相关信息,因此仍是能够比较快地定位到有问题的代码片断。

这样一来强测点稳妥全过,性能分也不赖。互测也很方便,直接用评测姬跑一遍就行,虽然最后只发现了别人的一处bug,果真A组都是大佬orz。

心得体会

这三次做业层层递进的,难度也一次次加大,尤为是第三次的多电梯,对设计架构的要求很高,若是在最开始没有把各个类之间的关系梳理清楚,那么功能实现起来就会重重受阻,甚至面临全盘重构的可能。

然而,这三次做业也是有共性的。对于我来讲,输入推入请求,电梯取出请求,这种"生产者-消费者"模型的核心没有变。只要能设计好架构,让耦合度降到最低,那么任意电梯数量、各类限制要求均可以轻松地知足。调度算法也应该封装起来,想用哪一种算法单独替换便可,不要由于算法而改变架构自己。

经过这个单元的训练,我对多线程编程有了深刻的了解,掌握了线程间通讯、同步、互斥的方法,保证线程的安全性。更重要的一方面是,设计架构的能力有了不小的提高,明白如何才能设计出高内聚、低耦合的程序,这对之后可能的企业工做将有巨大的帮助。

相关文章
相关标签/搜索