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

  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. js上拉刷新数据

    $(window).scroll(function () { //下面这句主要是获取网页的总高度,主要是考虑兼容性所以把Ie支持的documentElement也写了,这个方法至少支持IE8 var ...

  2. FPGA内部硬件结构简介

    我们知道FPGA内部有很多可供用户任意配置的资源,其中包括:可编程逻辑.可编程I/O.互连线.IP核等资源,很多学过数字电路的人都知道与或非门可以构成几乎所有的数字电路,但是FPGA内部最基本的主要单 ...

  3. Python一键获取日漫Top100榜单电影信息

    最近看到一个 UP 主做的视频,使用可视化动态图,把目前播放量最多的 UP 主一一列出来,结果第一名是哔哩哔哩番剧,第一名的播放量是第二名近 10 倍. B站的番剧数量,也是相对其他平台比较多的,而且 ...

  4. 【转发】基本adbui命令使用 可做图像识别

    原文请参考,很详细:hao1032/adbui 非常详细,感谢整理!!首先了解下 adb命令大全,adb最全的命令  

  5. Kivy中显示汉字的问题

    1. kivy中显示中文乱码和提示错误的原因: 编码问题 字体问题 2. 字体问题的解决 可以下载支持中文的字体文件ttf,我这里使用了微软雅黑中文简体msyh.ttf.我们在编写布局时可以直接在相关 ...

  6. C#网络编程入门之UDP

    目录: C#网络编程入门系列包括三篇文章: (一)C#网络编程入门之UDP (二)C#网络编程入门之TCP (三)C#网络编程入门之HTTP 一.概述 UDP和TCP是网络通讯常用的两个传输协议,C# ...

  7. eclipse中的Invalid text string (xxx).

    这个是说明在eclipse中引用HTML的时候,语法出现了不规范的错误 可以到https://www.w3school.com.cn/index.html里面找找对应对象的问题 我之前就是option ...

  8. Java实现 蓝桥杯 算法训练 字符串长度(IO无敌)

    试题 算法训练 字符串长度 问题描述 输入一个字符串,输出其长度. 输入格式 输入一个字符串 输出格式 输出字符串长度 样例输入 一个满足题目要求的输入范例. HelloWorld 样例输出 10 数 ...

  9. Java实现 LeetCode 556 下一个更大元素 III(数组的翻转)

    556. 下一个更大元素 III 给定一个32位正整数 n,你需要找到最小的32位整数,其与 n 中存在的位数完全相同,并且其值大于n.如果不存在这样的32位整数,则返回-1. 示例 1: 输入: 1 ...

  10. Java实现 蓝桥杯 算法提高 概率计算

    算法提高 概率计算 时间限制:1.0s 内存限制:256.0MB 问题描述 生成n个∈[a,b]的随机整数,输出它们的和为x的概率. 输入格式 一行输入四个整数依次为n,a,b,x,用空格分隔. 输出 ...