第一次作业:单部多线程傻瓜调度电梯

设计策略

  本次作业我才用的是生产者消费者模式,创建一个RequestList类,将输入线程InputThread作为生产者,负责将请求放入RequestList;将电梯线程ElevatorThread作为消费者,负责从RequestList中取出请求。通过synchronize实现两个线程的互斥访问。

代码分析

  • 类图 

  

  • 方法复杂度

   

  • 类复杂度

  

BUG分析

  此次作业在公测与互测中均未发现BUG,也没能在互测阶段hack成功。

第二次作业:单部多线程可捎带调度(ALS)电梯

设计策略

  第二次作业仍然可用生产者消费者模式,总体与上次一样。调度策略也按照指导书的说明使用ALS调度。在实现上,由于每次都通过调度器发送开关门、上下乘客的信号较为麻烦,因此我通过在电梯中增加一个Passenger请求队列,用来表示在乘坐电梯的人,电梯每到一层,就检查Passenger队列,若是有人的目的楼层在当前楼层,则电梯会自动开门,然后将此人从Passenger队列中剔除。当Passenger队列为空时,通过调度器调度电梯;否则,电梯会自己运行并在每一楼层更新Passenger队列,直到Passenger队列为空停止。这样的实现方法相比电梯的所有操作都由调度器管理来说要简单许多,但这样写就相当于电梯本身就带有调度器的功能,使得这两个类的功能有所重合,这不符合面向对象的设计原则,因此并不推荐这样的写法。

时序图

  

代码分析

  • 类图

  

  • 方法复杂度

  

  

  可见,Elevator类中有不少方法的复杂度都比较高,这也是此次设计中的不足之处。

  • 类复杂度

  

BUG分析

  此次作业中,我在线程退出的问题上存在BUG。本次作业我有三个线程,分别为电梯,调度器和输入线程,而调度器作为调度线程,理应在其他线程都已结束的情况下,再进行退出,可我的代码中,只要输入线程已经结束,那么调度器就会结束,整个程序就直接结束。这样会导致电梯中还有乘客未走出电梯,但电梯已经停止的情况。BUG的解决办法就是设置一个电梯线程的结束标志,当电梯线程输入线程都结束后,调度器才会结束。

  此次作业未发现他人BUG。

第三次作业:多部多线程智能(SS)调度电梯

设计策略

  仍然使用生产者消费者模式。

  此次作业我共启动了六个线程。分别为三个电梯、一个输入线程、一个调度器、一个楼层检测线程。每个电梯都有属于自己的ElevatorList与TransferList,即电梯请求与换乘请求,电梯只负责从ElevatorList中取出请求并按照请求将乘客送往指定位置,当乘客到达目的地后,楼层中就会出现该乘客,将该乘客的id加入到floorPassenger中。输入线程作为生产者,读入请求并将其加到RequestList中。调度器负责从RequestList中取出请求并进行分析,若是不需要乘客换乘的请求,则直接将请求加入到对应电梯的ElevatorList;若是需要乘客换乘,则将该请求拆分为两个请求,将第一个请求加入到对应电梯的ElevatorList,将第二个请求加入到对应电梯的TransferList中。楼层检测线程,则是不停检测floorPassenger与TransferList,只要有楼层中的乘客id与TransferList中的id相匹配,则将TransferList中的请求删除,并将该请求加入到对应电梯的ElevatorList,这样就可以解决需要换乘请求的先后顺序问题。

  由于此次作业我沿用了上次作业的代码,因此在实现可捎带功能的部分,设计原则依然存在与面向对象思想相违背的情况。

时序图

  

代码分析

  • 类图

  

  • 方法复杂度

  

  

  • 类复杂度

  

  这次作业由于要实现的功能更多,因此许多方法和类的复杂度都比较高。

BUG分析

  此次作业中未发现线程调度与设计上存在的BUG。

总结

根据SOLID原则进行整体评价:

  • SRP(单一责任原则):由于在二三次作业中电梯都覆盖了部分调度器功能,因此不符合。
  • OCP(开放性原则)   :后两次作业都沿用了之前的代码,代码可拓展性较好。符合。
  • LSP(里氏替换原则) :这三次作业只继承了Thread类,电梯对象的创建是通过参数设置完成的。符合吧。
  • DIP(依赖倒置原则)  :符合吧?
  • ISP(接口分离原则)  :本单元作业只用了Runnable接口。

体会与收获

  本单元重点集中在多线程上。

  第一次作业,是实现一个最简单的多线程。主要是为了熟悉线程的基本操作,例如线程的创建、结束等,只要了解synchronize关键字的用法,很容易就完成此次作业。

  第二次作业,本质上与第一次作业没有太多区别,但在功能实现上更加复杂,而且严格限制了CPU_TIME_LIMIT与REAL_TIME_LIMIT。因此,此次作业对于我们在线程调度上有一定要求,不能再像第一次作业那样暴力轮训,必须通过wait与notify等操作实现线程调度,否则就会出现TLE。此外,由于捎带功能的出现,导致代码更加复杂,若是出现BUG,也要求我们具有有一定的多线程调试能力。

  第三次作业,才是真正的综合实践:多部电梯,各个电梯可达楼层不同,速度也不同,可承载人数也不同,需要乘客等待、换乘,不再如同前两次作业般的傻瓜调度。要完成此次作业难度不是特别高,但想要真正优化好,就需要有良好的调度策略:调度器需要根据电梯内人数按照一定优先级分配请求,必要时还要让不用换乘的乘客实行换乘提高效率的目的。

  总的来说,经过本单元的锻炼,在多线程设计方面一定会有很大的提升。

  期待下个单元的主题。

2019_BUAAOO_第二单元总结的更多相关文章

  1. OO第二单元作业小结

    前言 转眼已是第九周,第二单元的电梯系列作业已经结束,终于体验了一番多线程电梯之旅. 第一次作业是单电梯的傻瓜调度,虽然是第一次写多线程,但在课程PPT的指引下,写起来还是非常容易:第二次作业是单电梯 ...

  2. BUAA面向对象设计与构造——第二单元总结

    BUAA面向对象设计与构造——第二单元总结 第一阶段:单部傻瓜电梯的调度 第二阶段:单部可捎带电梯的调度 (由于我第一次写的作业就是可捎带模式,第二次只是增加了负数楼层,修改了一部分参数,因此一起总结 ...

  3. 我永远爱着OOP——第二单元作业总结

    第二单元的电梯真是愉♂快呢,多线程编程作为java编程OOP中的重要组成部分,通过这一个单元的学习,我也是有了很多全新的认识 那么下面就先例行一下公事 三次作业分析 第五次作业 设计分析 实现的电梯是 ...

  4. 2019OO第二单元总结

    (1)设计策略 电梯第1次作业是一个傻瓜调度电梯,使用先来先服务原则,不用考虑捎带(可以认为电梯的载客量为1),因此比较简单,调度器用一个队列就可以. 使用生产者-消费者模型,输入线程是生产者,电梯是 ...

  5. oo第二单元作业总结

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

  6. OO第二次博客作业--第二单元总结

    第一次作业 1. 设计策略 第一次作业,一共三个线程,主线程.输入线程和电梯线程,有一个共享对象--调度器(队列). 调度的策略大多集中到了电梯里,调度器反而只剩下一个队列. 2. 基于度量的分析 类 ...

  7. 第二单元电梯调度作业 By Wazaki

    figure:first-child { margin-top: -20px; } #write ol, #write ul { position: relative; } img { max-wid ...

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

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

  9. OO第二单元电梯线程系列总结作业

    电梯系列第一次作业 功能描述: 傻瓜电梯无需考虑超载捎带 线程模式: Producer-Consumer Pattern 思路: 第一次作业是一个傻瓜电梯,分别有一个生产者生成电梯指令(也就是Inpu ...

随机推荐

  1. EntityFramework6之原生SQL

    原文:https://www.cnblogs.com/wujingtao/p/5412329.html 用EF执行SQL又比ADO.NET方便,特别是在执行查询语句的时候,EF会把查询到的数据自动保存 ...

  2. SSH整合 pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  3. 前端笔记之JavaScript(五)关于数组和字符串那点事

    一.数组 1.1数组概念 数组(array)是一个有序的数据集合.说白了,数组就是一组数.数组内部可以存放一个或多个单独的数据,整体组成数组. 定义数组最简单的方式:数组字面量. 数组的字面量“[]” ...

  4. 自动备份远程mongodb数据库并拉取到本地

    自动备份远程mongodb数据库并拉取到本地 目标: 远程服务器 .1中的mongodb数据拉回公司测试服务器中 .远程服务器中编写自动备份mongodb脚本 ①编写脚本 # vim /opt/bac ...

  5. JavaScript 当月第一天和最后一天

    1. 概述 1.1 说明 在项目过程中,有时候需要默认展示一个月的查询条件,即当月的第一天和最后一天. 2. 代码 2.1 代码示例 直接调用getFirstAndLastDay()即可得到当月的第一 ...

  6. java基础知识三 流

    Java 流(Stream).文件(File)和IOJava.io 包几乎包含了所有操作输入.输出需要的类.所有这些流类代表了输入源和输出目标. Java.io 包中的流支持很多种格式,比如:基本类型 ...

  7. Qt-c++桌面编程报错:qt.qpa.plugin: Could not find the Qt platform plugin "windows" in "",已解决

    语言:c++ 编译库:Qt GUI,qt5.12.1 软件类型:Qt application,qt桌面软件 运行平台:window 10 ?按照[https://www.devbean.net/201 ...

  8. inotify+rsync文件实时同步报错:usr/local/bin/inotifywait: error while loading shared libraries: libinotifytools.so.0:

    解决办法: ln -sv /usr/local/lib/libinotify* /usr/lib/ /usr/lib64/libinotifytools.so.

  9. 解决问题SyntaxError: Unexpected token import

    ES6语法的模块导入导出(import/export)功能,我们在使用它的时候,可能会报错: SyntaxError: Unexpected token import 语法错误:此处不应该出现impo ...

  10. 利用阿里云搭建frp实现外网远程桌面链接内网电脑

    主要应用场景:针对学生放假回家使用外网无法远程操作学校的服务器或者电脑,这里通过阿里云的云服务器搭建一个frp服务,实现内网穿透,从而可以直接通过远程桌面或者其他工具实现对校园网内的服务器或者电脑进行 ...