这一单元作业是围绕电梯调度进行展开,并引进了多线程的概念。与第一次作业比较类似,作业难度也是逐渐推进,从最开始的单部电梯先来先服务(傻瓜式调度),到之后的单部电梯可稍带调度,到最后的多部电梯分楼层调度。下面分别说明并分析一下三次作业的设计结构。

第一次作业

作业概述:程序的输入流会不定时随机投放若干用户请求,用户的请求包括出发楼层和目标楼层,电梯没有容量限额,在规定时间上内完成所有请求。

这次作业的意图是让大家对线程有一个初步的认识(因为用户请求不定时投放,电梯强制在线必须要用线程才能搞定),共享对象的加锁保护以及线程之间的同步控制。单论本次作业的难度还是很低的,我大概用了三四个小时就完成了本次作业。

设计策略

由于第一次作业只有正确性要求,没有性能分,所以我也就没费工夫想如何优化调度hhh,就直接写了个先来先服务的模型。尽管电梯很愚蠢,看着有人经过也不捎带一下。。。但是在正确性上有十分充足的保证。

实际上,第一次作业得电梯调度就是最经典得生产者消费者模型,整个代码也就分为了三个部分,两个线程。主线程也就是第一部分用来接收用户请求,也就是生产者,另一部分是共享对象用来存储请求队列,最后一部分是电梯线程用来从请求队列中获取请求,也就是消费者。

代码分析

设计图

各个类得作用请见设计策略。也没什么可具体分析的了。

度量分析

可以看出这次设计的层次还算不错,各个指标都没有特别高的。当然这是因为这次作业比较简单。

Bug分析

分析自己程序的bug: 这次作业没有bug。
分析他人程序的bug: 高工这块没有互测部分,但是也和同学私下互相讨论过,测试方法就是写几个测试样例看看结果是否正确,以及看看代码内部是否有明显的逻辑漏洞。均为发现错误。

第二次作业

作业概述:这次作业和第一次作业基本一样,也是一部电梯,同时没有人数限制。唯一的区别就是要完成捎带调度。当然说是增加了调度算法,但是实现起来还是十分容易的。只需要每次到达一层楼的时候看一眼该楼层是否存在相同运行方向的等待的人。

设计策略

基本和第一次作业一样,同样都是两个线程,分别是主线程读取用户请求,子线程运行电梯。共享队列实际上是内置在电梯中的,但是为了方便理解,我还是单独写了一个共享队列的类,但是并没有做成线程,只是经了一下手立马就发给了电梯的内置队列(自己骗自己hhh)

代码分析

设计图

度量分析

Bug分析

分析自己程序的bug:似乎还是没有bug。。。这次虽然还是没有bug,但是因为有了性能分,所以并不是满分。我也只是实现了指导书中推荐的捎带算法,没有考虑其他更好的优化方法。实在是打不过优化大佬们。。。
分析他人程序的bug:在和其他小伙伴交流的时候还是没有发现什么bug,有的同学是把所有请求都添加到电梯中,也就是不管这个人是向上走还是向下走,你先进来,先和我绕一圈回头我再送你去你的楼层。虽然很不符合实际,但是似乎比常规的捎带方法最终的时间还要短。。也是有点意思。

第三次作业

作业概述:这次作业有了很大的升级,分为了三个电梯,每个电梯可以停留的楼层还不一样,有的人还必须要换乘才能到达指定的楼层。各个电梯的速度也不一样。

设计策略

这次的设计结构不同于上述两次作业,要复杂很多。由于这个有三个电梯也就是有多个消费者,所以并不能像之前那样把共享对象写在电梯里面,而是要有一个调度器对所用请求指定电梯后,在电梯内部再进行二次调度,也就是可稍带调度。所以总体上是有五个线程,一个主线程接收请求,一个子线程作为主控用来处理请求队列的分发,剩下三个是电梯线程,用来处理每个电梯的调度以及电梯的运行。但实际上由于这里有的请求非常的麻烦,需要不同电梯协同工作才能完成,比如说请求要从20->3楼,而只有A电梯能停留20楼,只有C电梯能停留3楼。所以这种情况我的处理办法是先让A电梯停留在一个AC都能停留的楼层,比如说5楼,然后这时把请求发到5楼同时修改成一个新的请求为5->3楼,这样再把这个新的请求发送给主控的共享队列。也就是说除了Main线程是生产者以外,电梯内部也可以生产新的请求。至于是如何调度的,我的调度器十分简单,就是先判断是否有直达电梯,并将请求发给最近的直达电梯。如果没有可用的直达电梯(两种情况,直达满了,或者就是需要中转的)就给一个最近的电梯。电梯到每一层的运输规则都是写死的,比如如果能直达就直达就ok了,但像A电梯不能到3楼,所有通过A想去3楼的就都会送到5楼。显而易见,我这种方式绝对不优,甚至有时候很愚蠢。

代码分析

设计图

度量分析

可见Request类的sendRequest()函数的度量值很高,这是因为里面进行了非常对的if判断,来分类到底要给哪个电梯。

Bug分析

分析自己程序的bug:依旧没有bug。
分析他人程序的bug:我看的大多数小伙伴的代码bug主要集中在程序结束判断上。当然不同人写法不一样,但大体来讲不能简单通过Main线程的输入结束来判断是否要关闭主控线程,必须要等所有的电梯都结束了同时没有输入了才能关闭。

总结

先从课程作业体验上讲一下,总体感觉这一单元的体验要比上一单元好一些,代码写得也顺利很多,最多用一天就都能写完(难道是我进步了???)。
在说说多线程编程的体会吧,总的来讲前两次作业不需要太多的思考,简单加个同步锁就ok了。但是在第三次就了一些更深的感受,首先多线程debug就很不同,单步调试基本没啥用,print会更直接。其次就是加锁的艺术,有的时候全部加上锁肯定没问题,但是性能会下降很多,但是如果减少锁的范围可能又会出现不同步带来的bug,所以需要好好权衡和设计这块。

最后感谢老师和助教的帮助和指导!

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

  1. oo第二单元作业总结

    oo第二单元博客总结 在第一单元求导结束后,迎来了第二单元的多线程电梯的问题,在本单元前两次作业中个人主要应用两个线程,采用“生产者-消费者”模式和共享数据变量的方式解决问题.在第三次作业中加入多个电 ...

  2. OO第二单元优化博客

    OO第二单元优化博客 第五次作业没有性能分,但是,我在这一单元的宗旨就是写一个日常生活中 最常见的那种电梯,所以第五次我没有写傻瓜电梯,而是直接写了个\(look\),和第六次基本相同. 总计一下lo ...

  3. 【OO学习】OO第二单元作业总结

    OO第二单元作业总结 在第二单元作业中,我们通过多线程的手段实现了电梯调度,前两次作业是单电梯调度,第三次作业是多电梯调度.这个单元中的性能分要求是完成所有请求的时间最短,因此在简单实现电梯调度的基础 ...

  4. OO第二单元小结

    OO第二单元小结 一.三次作业代码分析. 1.第一次作业 第一次作业是单部电梯的傻瓜调度,由于其过分傻瓜,所以第一次作业我只有两个类,一个main,一个电梯,main类负责不断从输入流中读取命令,如果 ...

  5. OO第二单元多线程电梯总结

    OO第二单元多线程电梯总结 第一次作业 设计思路 Input为输入线程,负责不断读取请求并将读到的请求放入调度器中. Dispatcher为调度器,是Input线程和Elevator线程的共享对象,采 ...

  6. 电梯也能无为而治——oo第二单元作业总结

    oo第二单元作业总结 一.设计策略与质量分析 第一次作业 设计策略 在第一次作业之前,我首先确定了生产者--消费者模式的大体架构,即由输入线程(可与主线程合并)充当生产者,电梯线程充当消费者,二者不直 ...

  7. 2020北航OO第二单元总结

    2020北航OO第二单元总结 前言 本单元考察基于多线程的电梯调度问题,成功让我从一个多线程小白到了基本掌握了使用锁来控制线程安全的能力,收获颇多(充分体验了迷茫地de一个又一个死锁bug的痛苦). ...

  8. OO第二单元——多线程(电梯)

    OO第二单元--多线程(电梯) 综述 第二单元的三次联系作业都写电梯,要求逐步提高,对于多线程的掌握也进一步加深.本次作业全部都给出了输入输出文件,也就避免了正则表达式判断输入输出是否合法的问题. 第 ...

  9. OO第二单元作业总结【自我反思与审视】

    第二单元作业的完成史,就是一部心酸的血泪史…… 多线程的出现为我(们)打开一片广阔的天地,我也在这方天地摸爬滚打,不断成长!如果说第一单元之前还对Java语法有所了解的话,那么这单元学习多线程则完全是 ...

  10. OO第二单元(电梯)单元总结

    OO第一单元(求导)单元总结 这是我们OO课程的第二个单元,这个单元的主要目的是让我们熟悉理解和掌握多线程的思想和方法.这个单元以电梯为主题,从一开始的最简单的单部傻瓜调度(FAFS)电梯到最后的多部 ...

随机推荐

  1. 华为手机无法使用USB调试的解决方案

    在Android开发中,一直在使用华为的荣耀8进行调试,但是突然某一次,发现USB调试无法使用了,且在其他的电脑上进行调试也不行. 后来经过查资料,总算解决了此问题,在这里进行一下解决方案的记录. 需 ...

  2. 通过JDK常用工具监控Java进程的内存占用情况

    目录 1 JDK 工具的使用 2 查看 GC 日志信息 3 添加 JMS 远程监控 Tomcat是一款常用的Web容器, 它是运行在 JVM(Java Virtual Machine) 中的一个Jav ...

  3. requests使用“proxy”代理访问接口

    在requests中使用proxy代理访问 使用前先更新requests版本为支持socks的版本.   先pip安装对应库:  >> pip install -U requests[so ...

  4. Python猫荐书系列:文也深度学习,理也深度学习

    最近出了两件大新闻,相信大家可能有所耳闻. 我来当个播报员,给大家转述一下: 1.中国队在第 11 界罗马尼亚数学大师赛(RMM)中无缘金牌.该项赛事是三大国际赛事之一,被誉为中学奥数的最高难度.其中 ...

  5. Java日志正确使用姿势

    前言 关于日志,在大家的印象中都是比较简单的,只须引入了相关依赖包,剩下的事情就是在项目中“尽情”的打印我们需要的信息了.但是往往越简单的东西越容易让我们忽视,从而导致一些不该有的bug发生,作为一名 ...

  6. .Net 反射学习

    Why?为什么使用反射 MVC ORM EF 都是用的反射.反射可以让程序的扩展性,灵活性得到加强.一起即可动态创建   what 反射原理    动态加载类库 ,先添加引用类库,或者复制debug里 ...

  7. Python中使用type、metaclass动态创建方法和属性

    1: type() 我们知道动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Person的class: class Person(obj ...

  8. DataPipeline加入Linux基金会下OpenMessaging社区

    近日,国内领先的“iPaaS+AI”一站式大数据融合服务提供商DataPipeline宣布加入Linux基金会旗下OpenMessaging开源社区,将与OpenMessaging开源社区其他成员阿里 ...

  9. MIP开发教程(一) MIP-CLI工具安装与环境部署

    依赖安装 安装 MIP-CLI 创建开发文件结构 1. 依赖安装 MIP-CLI 使用 NPM 安装,依赖 node 环境: node 安装-windows node 安装-mac MIP-CLI 开 ...

  10. 最小生成树之Kruskal(克鲁斯卡尔)算法

    学习最小生成树算法之前我们先来了解下下面这些概念: 树(Tree):如果一个无向连通图中不存在回路,则这种图称为树. 生成树 (Spanning Tree):无向连通图G的一个子图如果是一颗包含G的所 ...