第五次作业

本次作业,需要完成的任务为单部多线程傻瓜调度(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。

心得体会

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

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

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

BUAA-OO-2019 第二单元总结的更多相关文章

  1. BUAA OO 2019 第二单元作业总结

    目录 总 架构 controller model view 优化算法 Look 算法 多种算法取优 预测未来 多线程 第五次作业 第六次作业 第七次作业 代码静态分析 UML 类图 类复杂度 类总代码 ...

  2. BUAA OO 2019 第一单元作业总结

    目录 总 架构 Controller​ Model​ 输入处理 代码静态分析 行数 方法复杂度 UML​ 类图 优点 缺点 坑 输入 非法的空白字符 输入的简并处理 运算 浅拷贝 可变类型与不可变类型 ...

  3. BUAA OO 2019 第四单元作业总结

    目录 第四单元总结 总 UML UML 类图 UML 时序图 UML 状态图 架构设计 第十三次作业 第十四次作业 课程总结 历次作业总结 架构设计 面向对象方法理解 测试方法理解与实践 改进建议 尽 ...

  4. 北航OO(2020)第二单元博客作业

    第二单元第一次作业 多线程设计策略 第一次作业的想法是设计三个线程:输入线程,调度器线程以及电梯线程.输入线程获取请求并发送给调度器线程:调度器线程通过查询电梯线程的状态(等待.停靠以及移动),并综合 ...

  5. BUAA OO 2019 第三单元作业总结

    目录 总 JML规格化设计 理论基础 工具链 规格验证 验证代码 代码静态检查 自动生成测试样例 生成结果 错误分析 作业设计 第九次作业 架构 代码实现 第十次作业 架构 代码实现 第十一次作业 架 ...

  6. 2019北航oo课程第二单元作业总结..#_#..

    学习了之前在写代码是从来没有见过的多线程之后,便迎来了此次电梯作业.说实话,这次作业做得十分的辛苦,虽然在前三次作业中领悟到了java面向对象的精髓,但是再加上了多线程之后,又开始理不清思路,对自己的 ...

  7. OO作业第二单元总结

    目录 一.设计策略 1 2 3 二.程序分析 1 2 3 S.O.L.I.D分析 三.Bug分析 1 2 3 四.互测策略 五.心得体会 一.设计策略 1 第一次完成的是一个傻瓜电梯,简单来说,就是来 ...

  8. 北航oo作业第二单元小结

    类的设计: 首先,我对我的思路进行整体的说明,由于我的三次作业,思路是继承的,所以做总体的说明 第一,   Main类,Main类自身并没有功能,他的功能只是构造需要的电梯线程和输入线程. 其中,第三 ...

  9. UML结构与解析——BUAA OO第四单元作业总结

    UML与解析架构 UML是什么 统一建模语言(英语:Unified Modeling Language,缩写 UML)是非专利的第三代建模和规约语言.UML是一种开放的方法,用于说明.可视化.构建和编 ...

  10. OO第二单元单元总结

    总述 OO的第二单元主题是电梯调度,与第一单元注重对数据的输入输出的处理.性能的优化不同,第二单元的重心更多的是在线程安全与线程通信上.这此次单元实验之前,我并未对线程有过了解,更谈不上“使用经验”, ...

随机推荐

  1. Git问题

    1. LF will be replaced by CRLF rm -rf .git // 删除.git git config --global core.autocrlf false //禁用自动转 ...

  2. centos安装安全狗提示Need system command 'locate' to install safedog for linux的解决方法

    今天为客户的centos服务器安装安全狗时提示Need system command 'locate' to install safedog for linux.Installation aborte ...

  3. 排序算法-冒泡排序(Java)

    package com.rao.sort; import java.util.Arrays; /** * @author Srao * @className BubbleSort * @date 20 ...

  4. 机器学习-MNIST数据集-神经网络

    #设置随机种子 seed = 7 numpy.random.seed(seed) #加载数据 (X_train,y_train),(X_test,y_test) = mnist.load_data() ...

  5. ESA2GJK1DH1K升级篇: STM32远程乒乓升级,基于(WIFI模块AT指令TCP透传方式),定时访问升级

    前言 学习此代码所需: 实现功能概要 定时使用http访问云端的程序版本,如果版本不一致,然后通过http下载最新的升级文件,实现升级. 测试准备工作(默认访问我的服务器,改为自己的服务器,请看后面说 ...

  6. 深入js系列-类型(null)

    首先null是表示什么状态呢 这个是需要和上篇的undefined做一个区分 undefined 从未赋值 非关键词(也就是可以定义为变量名或者赋值给它) null 曾经赋值.目前没值 关键词 typ ...

  7. 以V8中js源码为例了解GitHub查看代码功能

    GitHub作为开源仓库,许多开源项目仓库这里,当然不乏十分优秀的,比如Node.V8,我一直比较好奇js源码,像java的话,因为环境是JDK,我们结合IDE很容易就能跳转到其源码内部去查看实现,但 ...

  8. 复旦大学2018--2019学年第二学期高等代数II期末考试情况分析

    一.期末考试成绩班级前十名 丁思成(99).周烁星(97).王捷翔(96).顾文颢(92).顾天翊(90).封清(89).张思哲(89).李哲蔚(88).陈钦品(88).邹年轶(88).王祝斌(88) ...

  9. java calendar获取系统当前小时数

      calendar获取系统当前小时数 24小时制 Calendar calendar = Calendar.getInstance(); int curHour24 = calendar.get(c ...

  10. 【Gamma阶段】第七次Scrum Meeting

    冰多多团队-Gamma阶段第七次Scrum会议 工作情况 团队成员 已完成任务 待完成任务 卓培锦 编辑器风格切换(添加夜间模式) UI界面手势切换 牛雅哲 语音输入shell应用:基于pytorch ...