OO第二单元——多线程(电梯)
OO第二单元——多线程(电梯)
综述
第二单元的三次联系作业都写电梯,要求逐步提高,对于多线程的掌握也进一步加深。本次作业全部都给出了输入输出文件,也就避免了正则表达式判断输入输出是否合法的问题。
第一次作业——单部电梯(无调度)论述
第一次作业,是写一部电梯的模拟器,指导书提供了一个极为基础或者说不叫算法的算法,只需要将人送到正确楼层即可,对于时间、性能没有任何要求,但也是我们第一次尝试多线程,开始写代码时对于wait(),notify()函数并不是十分了解,导致出现了各种线程不安全,或是出现死锁的状况,代码写得也比较的复杂,架构并不是十分清晰。
性能分析
类
方法复杂度
明显可以看出run方法复杂度较高,其他方法为正常水平。
类复杂度
由于没有任何性能要求,我采取了接完一个人再去接另一个人的方法,效率极低,但可以保证正确性,建立了两个线程,一个Producer线程,负责读取输入,并放入共享队列中,另个一个Consumer线程,负责处理共享队列中的指令,并指导电梯上下移动,而在这次作业中我将电梯和Consumer写在了一起,也就是没有调度器线程,而只有生产者、消费者。
在后期,我也遇到了一些问题,比如结束程序的问题,我在Ctrl D后,并不能结束进程,而是卡在了一些死循环或是wait里,最终我也在用了信号量的情况下多加判断,结束进程。
第二次作业——单部电梯(ALS调度)论述
第二次作业,与第一次作业要求并无太大差别,只是增加了地下楼层,也就是负数楼层, 但在性能上有所要求,指导书给出了ALS算法,即捎带算法,在电梯运行过程中捎带路过楼层的乘客,相较于第一次作业的FAFS算法,有了很明显的进步,性能大大提高,难度也有所提高。输入输出接口仍然给好了jar文件,无需我们担心。下面先看一下IDEA对于我代码的分析。
类图

方法复杂度

复杂度较高的几个方法中都包含了较多的if条件判断,为确保正确性,只能以性能换正确。代码设计并不是十分到位。
类复杂度

第二次作业,我按照指导书使用了ALS算法,每到一个楼层,我会先让进程sleep(400),以度过开关门时间,然后检测电梯的等待队列中,是否有当前楼层的乘客在等待,若有则进入电梯乘客队列,接着遍历电梯乘客队列,将到达楼层为当前楼层的乘客送出电梯,每一次电梯运动前,都会更新一下当前的目标楼层,目标楼层也会综合考虑等待队列中的出发楼层,然后电梯根据目标楼层选择向上运动或向下运动,每运动一层为一个周期。
我认为这次作业的难点也就主要在调度一块,若是调度算法太差会导致Real-Time-Limited-Exceed,若是暴力轮询不sleep()会出现CPU-Time-Limited-Exceed,这也是我后面自己试出的一个小技巧,由于对于wait(),notify()两个方法的理解不到位,我的电梯内部采用暴力轮询,以防止错过任何一条指令或是进程在等待i队列还有指令的时候就结束。 但是我在获取指令的进程中采用了notify(),以唤醒get()方法中的wait()。
第二次作业我并不是十分成功,由于个人架构太失败,导致调度环节出问题,电梯运行方向并不会正确的改变,导致在强测时挂了多组数据,未能进入互测,这次作业我吸取了教训,知道一个不正确的架构,一定写不出一个正确的程序,在开始码代码前一定要考虑周全,想到程序运行的每一方面,尤其是结束进程方面,一定要在开始之初就设置好信号量,做好规划,而不能等到写完程序后在程序内部打补丁,强行结束程序。
第三次作业——三部电梯(自行调度)论述
第三次作业提高要求,设置为三部电梯,且每台电梯能够到达楼层互不相同,也就导致了需要乘坐两台电梯才能到达目标楼层的操作,且每台电梯运行速度,最大承载量也不相同,一开始我想使用继承,一个父类电梯包括电梯所有操作,然后用子类修改电梯的各种数据,造出三台电梯,但后来我发现了更加直接的方法,使用构造方法来确定电梯的几个参数,无需使用继承,且继承run方法我也不太确定是如何运行的。下面先看下IDEA的分析。
性能分析
类图
方法复杂度


复杂度高的函数如Tray.get(),因为三台电梯不同,导致获取的目标也不同,也就是用了if判断语句,增加了复杂度,但以后可以使用数组,传入index以减少if的使用,而在获取aimFloor一块,依然复杂度极高,毕竟有多种情况,我只能使用if判断,手动判断情况。
类复杂度

第三次作业我还是使用了生产者-消费者模式,由于会出现一台电梯无法送达的情况,我选择在当初将指令放入等待队列时,便拆分好,我会考虑所有的中转楼层,选取其中路线最短的中转楼层,然后将前一条指令先放入恰当的电梯中,后一条指令放在我的Monitor线程中,这是我新开的一个监视者线程,负责查看出电梯人员中,是否有id与监视者的等待队列中的id相同,若有,则该等待队列中的指令放入适当的电梯等待队列中,其他的架构都与第二次作业都差不多。
第三次作业的强侧表现也不太好,在这里我分享一下我debug的经历,我频繁出现CPU-Time-Limited-Exceed的问题,根据以往的经验判断,一定是暴力轮询没有sleep导致的,但我也并不是很清楚是哪一个while循环出现的暴力轮询,于是我才用输出debug的方法,在每一个while循环内部都都增加了输出,“XXX(类名):XXX(方法名) Here!”, 以判断哪一个while出现暴力轮询,当然输出结果极其恐怖,一个txt文件里面有25w+行的输出,显然找到了bug所在,但是自己在课下测试时并没有仔细测试。
这一次的经历也教会了我使用JProfiler,可以在Thread模块,查看是否有block,若是出现block,即代码内容有问题,然后使用输出debug,找到bug所在。
同时,在研讨课上,也有同学分享了System.error方法,可以输出错误数据,以后debug时可以尝试。
OO第二单元——多线程(电梯)的更多相关文章
- OO第二单元多线程电梯总结
OO第二单元多线程电梯总结 第一次作业 设计思路 Input为输入线程,负责不断读取请求并将读到的请求放入调度器中. Dispatcher为调度器,是Input线程和Elevator线程的共享对象,采 ...
- OO第二单元多线程电梯总结分析
一.概述 这一部分的作业考察的关注点与上一次的作业有所不同,上一次的考察重点主要集中在输入输出的判定以及多态的考察上面,而这一次是让我们进行多线程程序的调度与开发.这次开发过程中最大的感受就是自己之前 ...
- BUAAOO第二单元多线程电梯作业总结
第二单元多线程作业需要保证线程安全
- oo第二单元——多线程魔鬼电梯
在初步认识了面向对象思想后,立刻进入了多线程的学习,本单元的难点主要是锁的理解,需要保证线程安全的同时防止死锁的发生,也要尽可能缩小锁的范围,提高性能.这一单元以电梯为载体,让我们从生活出发,从电梯运 ...
- OO随笔之纠结的第二单元——多线程电梯
综述 主要任务就是写一个电梯模拟器,读入每一个人的请求然后让电梯把他们送到想去的地方. 从第一次到第三次作业,三次的主要任务都是相同的,但是每次都增加了很多的细节,每次的难度都逐步增长,电梯复杂度和瞎 ...
- OO第二单元总结——电梯调度问题
一.设计策略. 在三次作业中,多线程程序的实现分以下几个步骤: 1. 主线程Main类的创建多个线程. 2. 共享对象的synchronized锁保证线程之间的互斥访问. 3. 采用notifyAll ...
- OO第二单元总结——电梯
在电梯系列的作业中,笔者的整体架构几乎没有发生改变.现介绍如下,对于一个电梯系统,主要的工作步骤就是获取乘客请求.分派请求.执行请求.针对这样的工作模式,笔者设计了Elevator.Uselist两个 ...
- 电梯也能无为而治——oo第二单元作业总结
oo第二单元作业总结 一.设计策略与质量分析 第一次作业 设计策略 在第一次作业之前,我首先确定了生产者--消费者模式的大体架构,即由输入线程(可与主线程合并)充当生产者,电梯线程充当消费者,二者不直 ...
- oo第二单元作业总结
oo第二单元博客总结 在第一单元求导结束后,迎来了第二单元的多线程电梯的问题,在本单元前两次作业中个人主要应用两个线程,采用“生产者-消费者”模式和共享数据变量的方式解决问题.在第三次作业中加入多个电 ...
随机推荐
- python库--tensorflow
方法 返回值类型 参数 说明 张量 .constant() Tensort 张量 实例t value 创建一个常量tensor dtype=None 输出类型 shape=None 返回tens ...
- 部署yum仓库以及NFS共享服务
目录: 一.YUM概述 二.准备安装源 三.访问YUM仓库 四.本地YUM仓库 五.YUM工具概述 六.软件包查询.安装.卸载 七.NFS共享 一.YUM概述 YUM(Yellow dog Updat ...
- Python - poetry(2)命令介绍
poetry 语法格式 poetry [-h] [-q] [-v [<...>]] [-V] [--ansi] [--no-ansi] [-n] <command> [< ...
- JS预编译过程
GO和AO 变量的预编译 实例1 console.log(a); var a=1; console.log(a); 实际编译过程: 将a存入预编译对象中,赋值为undefined: 真正的赋值语句当程 ...
- CTFd+ubuntu service搭建等待更新
CTFd是一款基于Apache2.0的协议的开源CTF平台,最新版本目前为1.20.该平台功能强大,基本上能够满足目前的CTF竞赛需求,同时,该平台提供了强大的插件功能,可以自己进行插件开发实现自己的 ...
- POJ——3278 Catch That Cow(BFS队列)
相比于POJ2251的三维BFS,这道题做法思路完全相同且过程更加简单,也不需要用结构体,check只要判断vis和左右边界的越界情况就OK. 记得清空队列,其他没什么好说的. #include< ...
- C语言使用getch()读取方向键
初衷: 在解决N皇后问题时需要使用方向键实现布局切换,于是就在网上查找资料,感觉自己收获不小,就把自己总结的一些知识点给记录下来. 总结: 1.getch()读取字符需要一次. 2.getch()读取 ...
- 判断手机浏览器还是微信浏览器(PHP)
//判断是否 微信浏览器 function isWeixin1() { if (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== fa ...
- Docker系列(1) - Centos8.X安装Docker
环境准备 需要会Linux的基础 Centos8.x 使用Xshell连接远程服务器 环境查看 #系统内核是4.18以上 [root@localhost ~]# uname -r 4.18.0-305 ...
- Linux系列(29) - rpm包命名规则(1)
RPM包命名规则 例如包名:httpd-2.2.15-15.el6.centsos.1.i686.rpm 软件包名-httpd 软件版本-2.2.15 发布的次数-15 el6.centos适合的Li ...


