一.设计策略及程序结构分析

  1.第一次作业

  第一次作业是需要我们用多线程模拟一个实时电梯系统,功能比较简单正常,但要有捎带功能,我采用的调度策略便是指导书上提供的ALS调度策略,采用消费者-生产者模式,生产者即输入类,不断输入人的电梯请求,消费者就是电梯类,不断接受输入过来的电梯请求,并不断执行下去,中间的仓库类便是调度器,负责存储输入类即生产者提供的请求,并经过一定的调度策略将电梯请求交给电梯去执行.

  但调度器要获取电梯的实时状态,却不能一个线程直接调用另一个线程,所以我是采用了这样的设计策略.电梯存储自己的状态信息,并在电梯线程的每一个执行循环开始时,获取运行方向,电梯只负责是向上运行还是向下运行,不负责为什么向上运行和为什么向下运行.即电梯直接调用调度器的getDirection方法,获取向上还是向下的信息,传过去的参数有所在的楼层,当前的运行方向和电梯里正在执行的请求.调度器则根据电梯的状态和调度器里的等待队列判断出电梯的运行方向,将其返回给电梯,电梯每运行一层便重新获得运行方向,如此往复,将所有的电梯请求执行完毕.

  UML图如下:

  关于线程如何正确结束的设计方法便是当输入结束信号时,首先向调度器发送输入完毕的信号,即将调度器的end设置为true,并关闭输入线程,而电梯线程则在每运行一层后便检查是否输入结束和调度器和电梯里是否仍存在请求,若没有请求,则关闭电梯线程.

  线程间的协同和同步控制如图所示:

  2.第二次作业

  第二次作业仅仅是在第一次电梯的基础上增加了电梯的数量,最多有五部,并根据初始的输入电梯数目决定有多少个电梯运行,而电梯的类型等完全相同,但是电梯的载客量有了一定的限制,不能超载,所以总体来看第二次作业只需要在第一次作业的基础上进行一些调整和增加即可.

  我的设计策略便是增加一个主调度器线程,在电梯的专有调度器之上,负责不断接受来自输入的请求,并决定分配给5个电梯的调度器的其中一个,因为本人比较懒惰,又想不出比较好的多电梯调度算法,便直接听天由命,使用随机数来决定分配给哪个电梯,然后让电梯自己的调度器去处理.

  关于如何设置电梯的线程数目时,本人根据现实的生活中的情况,电梯不可能凭空消失也不可能凭空出现,所以在程序一开始便创建了5个电梯,但根据输入的电梯数目决定使用哪几个电梯,并将不使用哪个多电梯线程关闭,防止空跑消耗cpu时间.

  UML图:

  第三次作业(更细):

  第三次作业的要求瞬间变得多且复杂了起来,电梯的数目可在运行中增加,并且电梯的种类还各不相同,运行时间,载客量,可停靠楼层也都不一样,这遍瞬间增加了作业的难度,但是细细想明白后作业的难度也并不是很大.电梯的数目虽然可以增加,但是最大的数目还是只有6个,所以我还是依据现实中的情况,在程序一开始便设置了6个电梯,只不过另外三部电梯还没有初始化类型与姓名,让其停止在第一层.再后续跟进输入增加电梯时,便将电梯的类型和名称设置好并投入使用.第三次的总体框架仍然和第二次作业相类似,使用主调度器和电梯的专有调度器,只不过主调度器不是随便将请求传输给哪个专有调度器,而是根据现有的可运行的电梯和请求的类型来决定分配.

  因为电梯的可停靠楼层不一样,所以在输入类中我便将所有的输入请求需要换乘的全部拆分成了两个部分,并分别传给主调度器,拆分的策略是采用半动态式的拆分,根据目的楼层和起始楼层决定换乘的楼层,做到尽量经过的楼层较少.当然拆分的请求不能直接交给主调度器去执行,否则会因为时序问题导致两个相同的人同时坐不同的电梯的灵异事件.所以我将主调度器里的队列分成了两个部分,一个是一进入队列即可交付给电梯的队列,一个是拆分后的二次队列,拆分后的队列必须根据拆分前的请求是否执行完毕才能决定自己是否能够执行,这里是直接在每个电梯的专有调度器中增加了人员是否出电梯的数组,一旦电梯中的乘客出电梯,即可将对应ID的数组值设置为一,主调度器的拆分后队列在检查是否运行前判断这个数组值是否为1,若为1,则可交付给电梯执行.

  关于相同类型的电梯请求分配给哪个电梯,沿用第二次作业使用随机分配的方法,在对应类型的空闲电梯中随机选择一个电梯交付请求即可.至于载客量,运行时间等则可直接在电梯类和调度器类中进行扩展即可.

  UML图:

  

二.bug分析

1.自己debug

  神奇的是,这三次作业的中测在提交的过程中并没有出现WRONG ANSWER的情况,出现的大多是CTLE 和 RTLE,而这两者基本上都是同时出现,CTLE的出现往往是新增功能时莫名使用了类似于暴力轮询的结构,所以一旦出现,便对其进行wait,notify和sleep操作.而RTLE则是因为程序没有正确的结束或出现死锁,所有程序都在wait的状况中.这种的解决办法就是严密检查判断结束变量的取值与线程安全情况,而死锁的解决办法便是直接破除,采用其他方式达到相同的目的.

  当然极其伤感的是,第二次作业因为只花了2-3个小时便完成了,且中测交上去就直接过了,便满怀信心的直接pass,没想到强测栽在了载客量的限制上,因为我在判断是否超载的代码中的两个分支中只在前一个分支中进行了处理,另一个分支忘记处理了,导致了程序wa掉.

  对于RTLE的分析,我都是采用IDEA的自带THREAD分析和JPROFILE共同判断的操作,可以直接看见运行过程和多线程的之间的协调和wait,run关系.

2.hack别人

  因为WRONG ANSWER的构建可以采用随机生成数据的办法,且出现WRONG ANSWER的情况可能不多见,大部分人的错误都是可能出现在RTLE和CTLE上,所以我便构建了几组重复性很强的且执行性很强的数据,只坐一种电梯,且都是相同的路线,可能让线程不安全的程序出现错误.

三.总结和心得体会

  完成了三次电梯作业后,我不禁感慨道,终于不用像是第一单元的作业那样反反复复重构了,添加功能迭代还是轻松了许多,只需要增加了类和稍微修改代码即可达到迭代的目的.

  而我对于多线程的理解也不断地加深,线程安全尤为重要,如果不加处理的话,很可能会出现灵异事件,而且程序和线程也不能够正常的结束.当然,对于java的设计模式也在自己的实践和编程中不断地体会与掌握,最后最重要的是,学会了如何避免死锁这个大坑,再也不用你等我我等你了.

OO第二单元——兜兜转转之神秘电梯的更多相关文章

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

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

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

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

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

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

  4. oo第二单元作业总结

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

  5. OO第二单元优化博客

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

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

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

  7. OO第二单元学习总结

    前言: 第二单元总共包括三次电梯调度作业.这三次作业在笔者看来是为了让学生了解什么是多线程,多线程的好处及可能存在的潜在问题,对于多线程的安全问题应该如何解决和保证结果的唯一性和正确性.那么接下来笔者 ...

  8. OO第二单元小结

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

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

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

随机推荐

  1. JavaScript的基础语法及DOM元素和事件

    一,JavaScript是什么? 1,JavaScript简称:js,是一种浏览器解释型语言,嵌套在HTML文件中交给浏览器解释执行.主要用来实现网页的动态效果,用户交互及前后端的数据传输等. 2,J ...

  2. arch 系列manjaro更新deepin-screenshot没有图标

    问题描述 deepin软件安装到其他分支后,这个问题出现,相信各位一点都不意外,原因不细说,简单的概括就是没有DDE的桌面环境!! 简单介绍 deepin-screen截图软件在使用的时候是深受国人的 ...

  3. Life In Changsha College- 第四次冲刺

    第四次冲刺任务 整体功能实现. 用户故事 用户打开“生活在长大”的界面,选择登录 已注册过则输入用户名和密码直接登录 未注册用户则可选择注册功能,注册成功后登录 登录成功则弹出提示框 进行留言 系统结 ...

  4. GNS3配置问题(持续更新)

    GNS3配置问题 1.关于All in One的GNS3提示"判断dynamips版本失败"的解决办法 当我们找到GNS3根目录里的dynamips.exe,执行会报错告诉我们缺少 ...

  5. JavaScript 引用数据类型

    目录 1. 问题描述 2. 原因分析 3. React 中的引用数据类型 4. 业务场景 5. 参考资料 1. 问题描述 今天在写一个代码题时候, 有一个BUG 导致自己停滞好久, 该BUG 可以描述 ...

  6. 高性能可扩展mysql 笔记(一)数据库表、索引、SQL语句设计规范

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 项目说明:该笔记的背景为电商平台项目,电商项目由于其高并发.多线程.高耗能等特性,在众多的项目类型中涉及 ...

  7. Java实现 蓝桥杯 算法训练 Airport Configuration

    试题 算法训练 Airport Configuration 问题描述 ACM机场是一个本地机场,对于大多数人来说,机场不是他们的终点或起点,而是中转站.机场有一个规划图.到达的大门在机场的北边(相当于 ...

  8. Java实现 蓝桥杯VIP 算法训练 打印下述图形

    算法训练 4-1打印下述图形 时间限制:1.0s 内存限制:256.0MB 问题描述 使用循环结构打印下述图形,打印行数n由用户输入.打印空格时使用"%s"格式,向printf函数 ...

  9. Java实现 LeetCode 47 全排列 II(二)

    47. 全排列 II 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [1,1,2] 输出: [ [1,1,2], [1,2,1], [2,1,1] ] class Solut ...

  10. Java实现LeetCode_0013_RomanToInteger

    package javaLeetCode.primary; import java.util.HashMap; import java.util.Map; import java.util.Scann ...