BUAAOO第二单元总结之电梯问题
---恢复内容开始---
Homework1 傻瓜电梯
程序架构
第一次题目非常简单,思考也非常简单,一部电梯傻瓜调度。将命令入公共的队列,电梯从公共队列中取命令即可,其中只需要使用ArrayBlockingQueue就可以使线程安全,并不需要加上锁,因为只有这个队列需要公共访问修改,使用阻塞队列即可。
同步控制
第一次作业结构简单,只需要使用ArrayBlockingQueue就可以实现同步控制。
BUG的出现
1.使用电梯取队列命令时,若也使用阻塞取,就可能使整个线程阻塞而无法退出,因此我是用poll进行取。
2.程序退出不能仅仅判定输入为NULL,还得注意命令队列是否为空,不然将导致命令还没执行完就退出。
Homework2 捎带电梯
程序架构
这一次作业对电梯的架构做了很大的调整。它与第一次是完全不同的,因为第一次过于傻瓜,其实整个电梯类并不是电梯,而是一个运算器,对from和to两个floor进行运算时间即可,本质上并不是电梯。
所以首先我得明确什么是捎带,什么是电梯,捎带就是电梯仍然就是这么去接人,只不过接人的路上可能可以捎带上别人,它的接人方向和放人方向始终没有任何变化,因此我就将电梯的属性做了很大的调整,楼层的概念变得没那么重要,而方向作为主要属性,接人方向,放人方向和接人的极限层(即从接人任务结束的那一层)作为电梯每次开始运作的基础,然后每一层再给它分配任务,而不对这三个属性做任何变化。
比起第一次的傻瓜电梯,多加了一个调度器类,同时将请求队列放在了调度器中(调度器并不是一个线程,只是一个普通类,在电梯要调用时调用)。电梯多了outelelist和inelelist两个数组,用于存储在电梯外等候的人和在电梯里的人。电梯以pick和put为一次流程,每一次流程给电梯设置pick的方向和put的方向,以及pick的楼层,然后电梯开始运行,每当运行到一个楼层(初始层也算),就给电梯分配可以捎带的任务并且加入到电梯的outelelist,并且检索outelelist是否有可以进入电梯的,有就加入inelelist(等于人进电梯),并检索inelellist检索是否有达到楼层的,有就从inelellist移除(等于人出电梯),这些操作就完成了这一层的任务,并继续运行直到pick和put结束。
同步控制
虽然第二次设计复杂了很多,但是其实被线程共享的数据只有主请求队列,而电梯内部的两个接人放人数组都是私有的,只为电梯线程使用,因此不需要控制,所以我主请求队列仍然使用阻塞队列即可。
BUG的出现
1.起初我数组遍历使用下标从小到大进行遍历并且检索到就用数组的remove,这就会导致当我remove一个元素之后使size变化而下标i继续增长,某些元素无法检索到,解决办法就是从大到小遍历。
2.在调度器每次给电梯设置pickdirection时,将正确的direction传递给电梯,然而调度器内部记录的direction没有变化,导致会增加一些不能经过的捎带任务,从而使电梯不断爬楼却无法到达捎带楼层而无限爬楼。
Homework3 捎带电梯+多部不同的电梯
程序架构
复杂度控制还行
电梯类
电梯和调度器的时序图
类的数量并没有变化,依然是电梯类,调度器类,输入类,和主类。电梯完全可以复用,只要设置上升下降速度,载客量,可停靠楼层,开关门时间就可以将多部电梯一样操作。
多部电梯和任务的关系是竞争关系,电梯去竞争任务而不是靠调度器调度任务,对调度器加锁,每次只有一部电梯可以进行调度,其他电梯就得等待。
对于载客量的限制,只要调度器每次判定电梯的总任务数量是否超过载客量(包括电梯内的和电梯外的),只要超过就不派发。
对于楼层问题,直达楼层就如作业二一样,并没有任何变化。而对于不直达楼层,我们需要对其进行分割,将其分成两个可以直达的任务,即分割第一任务和分割第二任务,这就需要解决以下几个任务:1.何时分割。我在Input类就进行了分割操作,一输入并不马上加入任务队列,而是先进行分割操作。2.如何保证先做完分割出的第一任务,再执行第二任务(即先送到中转楼层,再去接他到目的楼层,不然会造成去接但是人还没到的情况),因此我在调度器中加入了waitqueue和wastequeue,waitqueue存储的就是分割出来的第二任务,而wastequeue是电梯inelelist中被remove的元素。每次调用调度器,就检索整个wastequeue,查找其中是否有和waitqueue中相同的id(因为中转的是同一个人),有就把waitqueue中的请求加入主请求队列等待电梯竞争,没有就找下一个,并且把wastequeue的元素都清空。这样就可以保证时间的先后性,但是多次的循环检索可能会造成计算时间过长。
同步控制
新增的waitqueue和wastequeue都为多线程共享,因此我将其都调用线程安全类,使用ArrayBlockingQueue和ConcurrentHashMap两个类,保证其线程安全,同时在使用调度器的代码块加上锁,从而保证每次只有一部电梯调用调度器。这样就完成了整个同步控制流程。
BUG的出现
这次最严重的bug就是时间问题,CPU常常超出所规定的时间,原本我采用第二次作业的版式,只在电梯类的最后加入一条sleep()指令来完成暂时的休眠,然而第三次作业的调度器类太过于臃肿,其中循环检索太多使CPU运行时间过长,所以我就在每次调用调度器就notifyall并wait,并且在调度器内部也穿插了sleep,然而这就会导致另一个问题,当另外两个电梯结束线程后,就会使最后一个电梯永远停留在wait状态,于是我就使用wait(time),当wait超过time的时间就自动唤醒,从而解决了一个电梯运行的无限等待问题。
查找BUG策略
对于自身BUG查找,使用print法,在每次线程调度的开头和结尾都使用print,并且使用部分模拟数据来测试。
对于查找他人BUG,并没有很好的办法。
三次作业总结
这三次作业,让我对于多线程编程有了更加深刻的认识。它和单线程有着很大的差别,对我们的编程能力有着很大的考验,这就需要我们严谨的架构能力和对线程安全的重视。 我的架构能力确实有所提升,第二三次作业都是使用同一个架构。然而我对同步控制仍然还有很大缺陷和漏洞,我仅仅使用简单的线程安全类和一把锁,锁的范围过大也导致了某部分代码块需要运行过久时间,对notify和wait的使用也仍然生疏,这还需要多加练习。
BUAAOO第二单元总结之电梯问题的更多相关文章
- OO第二单元——多线程(电梯)
OO第二单元--多线程(电梯) 综述 第二单元的三次联系作业都写电梯,要求逐步提高,对于多线程的掌握也进一步加深.本次作业全部都给出了输入输出文件,也就避免了正则表达式判断输入输出是否合法的问题. 第 ...
- BUAAOO第二单元多线程电梯作业总结
第二单元多线程作业需要保证线程安全
- 2019年北航OO第二单元(多线程电梯任务)总结
一.三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程.这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以 ...
- OO第二单元作业——魔鬼电梯
简介 本单元作业分为三次 第一次作业:第一次作业要实现单部简单电梯,停靠所有楼层,无载客容量,性能分考量电梯运行时间. 第二次作业: 第二次作业实现多部电梯,电梯数量由初始化设定,每部电梯都停靠所有楼 ...
- BUAA-OO第二单元小结
一.设计策略 三次作业中,由于前两次作业都只有一部电梯,因此我的线程只有两个,一个等待队列输入进程,以及一个电梯运行进程.等待队列输入进程实现十分简单,只需要根据输入把request添加到等待队列即可 ...
- BUAAOO第二单元代码分析
第一次作业 设计思路与感想 第一次作业是要求有捎带的电梯实现, 第一次作业是花费的时间比较长的一次,花费了很多的时间去思考架构的问题.起初是想要搞三个线程的:输入线程,调度器线程和电梯线程,想要搞一个 ...
- oo第二单元——多线程魔鬼电梯
在初步认识了面向对象思想后,立刻进入了多线程的学习,本单元的难点主要是锁的理解,需要保证线程安全的同时防止死锁的发生,也要尽可能缩小锁的范围,提高性能.这一单元以电梯为载体,让我们从生活出发,从电梯运 ...
- OO第二单元总结——多线程电梯
第五次作业分析 1.设计策略 调度器采用单例模式,内部设请求队列,对请求队列的一切操作(查.增.删)都在调度器内完成,且都要求串行,从而确保线程安全.接收器和电梯是两个线程:接收器接受请求调用调度器来 ...
- 第二单元电梯调度作业 By Wazaki
figure:first-child { margin-top: -20px; } #write ol, #write ul { position: relative; } img { max-wid ...
随机推荐
- 自动化pip安装
其实正确安装python3.6后,在安装目录里就有pip.exe文件,只不过用的时候,要进入pip的安装目录下进行安装numpy等. 如进入这个目录, D:\Program Files\Python\ ...
- Clover 安装 Mac 系统更新 (原版黑苹果)
关于使用原版镜像(即 .dmg )安装黑苹果的升级,笔者写写自身经验吧. 在Clover启动的界面中与Mac OS有关的启动菜单有以下这些: Boot FileVault Prebooter from ...
- Testlink与MantisBT集成
Testlink与MantisBT集成 关于两者集成的文章网上有很多,但是有些文章可能是作者写的时候自己不理解或有纰漏,有些文章写得是不够详细导致在配置中遗漏什么导致不成功.经过一天的不停尝试,终于完 ...
- aop (权限控制之功能权限)
在实际web开发过程中通常会存在功能权限的控制,不如这个角色只允许拥有查询权限,这个角色拥有CRUD权限,当然按钮权限显示控制上可以用button.tld来控制,本文就不说明. 具体控制流程就是通过登 ...
- Crashing Robots(水题,模拟)
1020: Crashing Robots 时间限制(普通/Java):1000MS/10000MS 内存限制:65536KByte 总提交: 207 测试通过:101 ...
- centos中redis安装
一.wget http://download.redis.io/releases/redis-4.0.2.tar.gz 二.tar xzf redis-4.0.2.tar.gz cd redis-4. ...
- cryptoJS
CryptoJS通俗的来讲是为了安全性,将前端传递到后端的参数加密 加密/解密方法(对称加密算法) AES 高级加密标准,是下一代的加密算法标准,速度快,安全级别高 DES 数据加密标准,适用于大量数 ...
- xadmin邮箱验证码 标题 EmailVerifyRecord object
[修改users-models模块] 1.如果这样不生效 def __unicode__(self): return '{0}({1})'.format(self.code, self.email) ...
- ionic2使用cordova打包的环境搭建
1.安装node.js(不用说了) 2.安装JDK(java的开发基础类库) 3.安装SDK(安卓开发集成包) 4.gradle( JAVA界的Weboack ,支撑app的编译,打包的流程) 5.安 ...
- System.exit()源码分析
最近代码中常用的System.exit(),就来看看源码. 首先位于java.lang.System中,源码如下: /** * Terminates the currently running Jav ...