OO第二次单元总结——电梯多线程调度问题

在这个单元OO学习中,我们终于迎来了期待已久(不是)的电梯多线程调度作业,开启了OO打怪之路的新关卡。虽然说经过了这三次作业,我对于多线程的理解还不能算是熟练,在线程控制方面的实现也仍有缺陷,但是经过了磕磕绊绊的写作业过程也达到了可以对多线程进行简单应用的程度。在此,我对于第二单元的OO作业进行一个总结,梳理一下自己这三次作业中的实现方式以及所踩过的大雷。


第一次电梯作业

(1)设计策略

  • 题目要求

    单部多线程傻瓜调度(FAFS)电梯的模拟,实现对于一个目的选择电梯的傻瓜调度。

  • 设计思路

    在第一次的电梯作业中,我基本是严格按照指导书中建议的构架模式进行电梯调度。

    考虑到对于输入和电梯,等待人员队列是共享的,所以我将队列作为共享变量在输入和电梯之间传递。除此之外,我将输入操作放入了主线程中,并将得到的等待人员信息传入队列中进行添加等操作。对于电梯,则单独开了一个线程,该线程可以读取队列类的信息,并依次对队列中的等待人员进行输送的操作(本次作业没有考虑捎带和优化,使用的是最为傻瓜的调度方式——按次序读取等待人员并操作——先来先送)。

(2)基于度量分析程序结构

  • 总体结构介绍

    在本次作业中,我总共分了4个类——一个主线程类、一个电梯线程类,还有另外两个辅助类——人员信息变换格式类、电梯运行类。其中,在主线程中进行输入操作,并且主线程中包含共享的队列,输入后的信息存储如队列以供电梯进行获取,电梯不断进行轮询直至队列内为空且输入已关闭。

  • 类图

从类图中可以明显地看出整个程序的结构,由于第一次电梯作业还算比较简单,所以构架也很清晰,但是由于没有进行调度器的考虑,导致我到第三次电梯作业时的程序架构上出现比较大的问题。

  • 主要度量图

由于本次作业的实现比较简单,需要的交互也不是很多,代码量也没有很大,所以在本次作业的代码构架方面没有出现什么问题。

  • UML的协作图(sequence diagram)

  • SOLID原则分析

    S(单一功能原则):本次作业主要有三个部分——输入、调度和运行,基本实现了不同的类有着不同的功能。

    O(开闭原则):由于在本次作业中没有使用接口和继承,所以该原则没有办法遵守。

    L(里氏替换原则):本次作业中没有涉及多态。

    I(接口隔离原则):本次作业没有使用接口。

    D(依赖反转原则):在本次作业中由于需要实现的功能仍不是很多,所以高层次对低层次的依赖还不是很强。

(3)bug分析

由于这次的作业比较易于实现,并且代码结构没有那么复杂,所以我没有发现自己和他人的bug。


第二次电梯作业

(1)设计策略

  • 题目要求

    单部多线程可捎带调度(ALS)电梯的模拟。该电梯可由-3层到-1层,1层到16层。

  • 设计思路

    在第二次电梯作业中,我也主要是按照指导书上的方法写的。将需进入电梯的请求分为两类——主请求和被捎带请求,将电梯内的人员作为一个list。

    在这次作业中,我为等候人员队列开了一个单独的类。当电梯中list的size为0且等待队列不为空时,首先考虑使等待队列中的等候最久的人进入电梯。同时,在经过每层时,都对是否有人员需要在此层上下进行分析,做到捎带。

  • 优化

    在做本次作业时,为了做到正确性(虽然最后也没做到),没有进行过多的优化。现在想想,在电梯为空时,应当选择离当前楼层最近的一个等待人员进行进入电梯操作,这样能够减少空电梯自己跑这种浪费时间的现象。

(2)基于度量分析程序结构

  • 类图

本次作业我基本延续了上次的结构。主要的不同之处是将等待队列提取出来,通过调用FloorList类进行操作。但是问题还是在于我仍然是直接在Elevator类中进行调度,应该单独开设一个调度器。

  • 主要度量图

可以明显地看出由于直接在Elevator类中进行调度,导致Elevator类的复杂度相较于其他的类过高。这也提醒我在以后的代码编写时要更好地简化类,区分不同的功能。

  • UML的协作图(sequence diagram)

  • SOLID原则分析

    S(单一功能原则):同上次作业相同,本次作业主要有三个部分——输入、调度和运行,基本实现了不同的类有着不同的功能。(但是其实调度部分可以更加细化,目前实现调度功能的类过于复杂。)

    O(开闭原则):本次作业中没有使用接口和继承。

    L(里氏替换原则):本次作业中没有涉及多态。

    I(接口隔离原则):本次作业没有使用接口。

    D(依赖反转原则):在本次作业中还是仍然依赖于具体的类。

(3)bug分析

  • 自己的bug

    本次作业在强测上栽了比较大的跟头,但是仔细看了一下自己的代码,发现其实只是一处控制关门的信号应该为0的时候写成了1。然而这一个只有一字之差的错误却使我的强测只对了3个点(欲哭无泪)。这血泪的教训也提醒我在之后写代码时一定要思路清晰,并且要全面进行debug,并仔细查看一遍自己的代码。

  • 他人的bug

    在本次互测中,由于不知道该如何造出易错数据而没有能够找到他人的bug。


第三次电梯作业

(1)设计策略

  • 题目要求

    多部多线程智能(SS)调度电梯的模拟。总共有三部电梯,分别只能停靠规定的楼层,每个电梯的最大载客量也不尽相同。

  • 设计思路

    在基本构架上,我基本延续了第二次电梯作业的思路(除了对于上空电梯的等待人员的选择上进行了一些优化),但是将轮询改为了wait、notify方式。主要分为了四种类:主线程中含有输入操作,等待人员队列为一个单独的类,电梯的调度过程为一个类,人员的类型为一个类。

    在进行 输入时,我首先进行的是对于人员进行分类——主要可以分为9种状态:只用A电梯即可送达、只用B电梯即可送达、只用C电梯即可送达、A->B(不能只用A电梯的情况下)、A->C(不能只用A电梯的情况下)、B->A(不能只用B电梯的情况下)、B->C(不能只用B电梯的情况下)、C->A(不能只用C电梯的情况下)、C->B(不能只用C电梯的情况下)。

    在本次作业中最主要的问题在于当等待人员上楼和下楼的楼层无法用同一个电梯满足时,应该如何使其更换电梯。在此处我进行了一些优化,将人员可以进行更换电梯的楼层根据他们本身处于的楼层设置一个区间,若本身就有人员在此处上下,则可以顺便将这个人放下,节约一些开关门的时间。

  • 优化

    在最初的代码完成之后,我一直在思考怎么进行进一步的优化。在第一个代码版本内,每一个人员的状态是不能够重合的,这就面临着一个很消耗时间的问题,若电梯已经满了,且还有人员没有上去,那么本身这些人员是可以运用另一种方法被运送的,但是在这种情况下这能等待。但是当我完成代码的改写后,发现除了在这种比较极端的情况下速度可以将近快出一半以外,在其他的情况下并不能很大幅度地提升速度,甚至还会出现很多bug(栽了强测)。

    除此之外,考虑到每个电梯的速度不同,所以在编写代码时,还可以对于电梯的选择进行控制,如在既可以上A电梯也可以上B电梯的时候需要保证上A电梯。

    在我的代码中,还有一个比较花费时间的问题是我都是采用先上后下原则,所以很多情况下能够一起带走的人员却被留到了那里,所以其实还可以将电梯调节成为先下后上,这样便可以节省很多电梯多次来回跑的时间。

(2)基于度量分析程序结构

  • 类图

由类图中可以看出,本次的程序结构与第二次电梯作业差不多。这个构架在前两次电梯作业中都没有什么问题,但是可以发现,在本次作业中,由于程序更加复杂,所以每个类的函数及变量变得更加复杂。

  • 主要度量图

从度量图中可以看出,在本次电梯作业的代码中,由于函数中判断语句过多,类的功能划分不明确,许多类和函数都在复杂度上出了问题。明显可以看出用于调度的代码的行数过多,应该将其的功能更加细化,并按照功能多划分几个类。

  • UML的协作图(sequence diagram)

  • SOLID原则分析

    S(单一功能原则):在本次作业中,可以明显看出在电梯调度方面没有进行进一步的功能细化,导致一个类承担了多个功能的实现。

    O(开闭原则):本次作业中没有使用接口和继承。

    L(里氏替换原则):本次作业中没有涉及多态。

    I(接口隔离原则):本次作业没有使用接口。

    D(依赖反转原则):在本次作业中主要依赖于具体的类,没能符合依赖反转原则。

(3)bug分析

  • 自己的bug

    由于在进一步优化的时候没有进行更加全面的思考,完全是补丁式的优化,导致在很多时候程序的运行无法按照控制进行。

    当然,问题出现的主要原因还是在自己debug的时候没能进行全面的测试,比如说,我在自己测试的时候测了B->C的情况,却没有测C->B的情况,而程序也就是在这里翻了车(后悔莫及)。

    • 经验教训

      以后在自己进行测试的时候,数据一定要构造的更加全面,一定不要想当然。应当根据题目的意思构造覆盖各种情况的数据。

  • 他人的bug

    这次作业bug的随机性还是比较大的,主要我认为会出现在三个错误上:

    1. 停不下来

      这是主要需要构造一些较为复杂的数据集,其中需要包含各种情况,这样便比较容易命中bug。

    2. 人没进去

      这个人工de还是很困难的,主要方法有观察代码并进行分析、碰运气

    3. 线程出现不应该的error信息

      这种情况主要是由于在人员出电梯是没有将循环变量减1,导致随后出现error现象。


心得体会

  • 线程安全

    在目前编写多线程的经历中,我认为线程安全最重要的还是解决如何对于共享变量加锁的问题。

    在这三次作业中,我主要使用synchronized对于共享的方法、对象进行上锁,并且使用notifyAll将锁进行释放。

    除此之外,还可以使用原子类保证我们对这些类进行操作时是线程安全的。

  • 设计原则

    这三次电梯作业没有能够很好地符合SOLID原则,在代码编写时没有过多地考虑进行类的抽象,也没能使每个类的功能更加具体,导致代码过分冗长。

    对于接下来的oo作业,需要在每次代码的编写前都更加清晰地知道自己需要实现哪些功能,并再将功能进行细化。

通过这三次多线程电梯的作业之后,我目前对于多线程总算是入了个门,但是前路漫漫,在今后的oo之旅中,我也需要加强自己对多线程的理解,使自己的代码能够更加坚不可摧,而不是在发现bug后对着满目疮痍的代码打补丁。

OO第二次单元总结——电梯多线程调度问题的更多相关文章

  1. OO第二次单元总结

    OO第二次单元总结 前言 第二单元的三次作业:系列电梯与多线程. 第五次作业 (1)设计策略 电梯的第一次作业是单部傻瓜电梯,采用FAFS调度策略,电梯按队列顺序依次处理请求,单次只处理一个请求.本次 ...

  2. OO第二单元总结(多线程的电梯调度)

    经过第一单元作业的训练,在做第二单元的作业的时候,要更加的有条理.但是第二次作业多线程的运行,带来了更多的运行的不确定性.呈现出来就是程序会出现由于线程安全问题带来的不可复现的bug.本单元的作业也让 ...

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

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

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

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

  5. oo第二单元——多线程魔鬼电梯

    在初步认识了面向对象思想后,立刻进入了多线程的学习,本单元的难点主要是锁的理解,需要保证线程安全的同时防止死锁的发生,也要尽可能缩小锁的范围,提高性能.这一单元以电梯为载体,让我们从生活出发,从电梯运 ...

  6. OO第二单元电梯作业总结

    目录 目录一.第一次作业分析设计策略基于度量分析程序结构二.第二次作业分析设计策略基于度量分析程序结构三.第三次作业分析设计策略基于度量分析程序结构四.分析自己程序的bug五.发现别人程序bug所采用 ...

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

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

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

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

  9. 多线程编程初探——OO第二单元作业回顾

    一.作业设计策略 1)执行FAFS策略的单部电梯 ​ 由于对多线程不是很了解,于是采用了理论课上介绍的生产者消费者模型作为设计模板(也是很多同学一开始的做法):将请求队列作为共享对象(托盘),名为In ...

随机推荐

  1. 【转载】shell实例手册

    原文地址:shell实例手册  作者:没头脑的土豆 shell实例手册 0说明{ 手册制作: 雪松 更新日期: -- 欢迎系统运维加入Q群: 请使用"notepad++"打开此文档 ...

  2. C# Timer定时器用法

    System.Timers.Timer timer1 = new System.Timers.Timer(); timer1.Elapsed += new System.Timers.ElapsedE ...

  3. JavaScript的本地对象、内置对象、宿主对象

    首先解释下宿主环境:一般宿主环境由外壳程序创建与维护,只要能提供js引擎执行的环境都可称之为外壳程序.如:web浏览器,一些桌面应用系统等.即由web浏览器或是这些桌面应用系统早就的环境即宿主环境. ...

  4. SVN合并时报错:合并跟踪不允许丢失子树Merge tracking not allowed with missing subtrees; try restoring these items

    使用的是TortoiseSVN; Merge tracking not allowed with missing subtrees; try restoring these items 下面会有跟着几 ...

  5. iTextSharp 使用详解(转) 感谢原著作者 .

    TextSharp是一个生成Pdf文件的开源项目,最近在项目中有使用到这个项目,对使用中的经验作一个小结. ITextSharp中相关的概念: 一.Document 这个对象有三个构造函数: 隐藏行号 ...

  6. 【Leetcode】【Hard】Copy List with Random Pointer

    A linked list is given such that each node contains an additional random pointer which could point t ...

  7. POP动画[1]

    POP动画[1] pop动画是facebook扩展CoreAnimation的,使用及其方便:) 1:Spring系列的弹簧效果(两个动画kPOPLayerBounds与kPOPLayerCorner ...

  8. mysql那些招

    show table status mysql官方文档在 http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html 这里的rows行是 ...

  9. dADas

    Linux(Centos)之安装Nginx及注意事项 - Kencery - 博客园   怪才(Kencery) 菜鸟的里程中只有奋斗,别无其他 博客园 首页 新随笔 联系 订阅 管理   Linux ...

  10. join语句中on条件与where条件的区别

    大纲:on是在生成连接表的起作用,where是生成连接表之后对连接表再进行过滤 当使用left join时,无论on的条件是否满足,都会返回左表的所有记录,对于满足的条件的记录,两个表对应的记录会连接 ...