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

设计策略

  本次作业我才用的是生产者消费者模式,创建一个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. dubbo基本信息

    1.Dubbo是什么? Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC 分布式服务框架,现已成为 Apache 基金会孵化项目. 面试官问你如果这个都不清楚,那下面的就没必要问了. 官网: ...

  2. I2C通信基本原理及其实现

    I2C是一种总线式结构,它只需要SCL时钟信号线与SDA数据线,两根线就能将连接与总线上的设备实现数据通信,由于它的简便的构造设计,于是成为一种较为常用的通信方式. 由于I2C采用的是主从式通信方式, ...

  3. 【codechef】FN/Fibonacci Number

    题意 给出 c 和 P ,求最小的非负整数 n 使得 \(Fib(n)=c(mod~ P)\) 其中 P 是质数且 模 10 等于一个完全平方数(也就是说 P 的末位是个完全平方数,那么只能是 1 或 ...

  4. 启动Eclipse发生错误:An internal error occurred during: "Initializing Java Tooling".

    问题描述   由于上一次关闭 Eclipse 时没有正常关闭,再次启动 Eclipse 时报错:An internal error occurred during: "Initializin ...

  5. 以慕课网日志分析为例-进入大数据Spark SQL的世界

    下载地址.请联系群主 第1章 初探大数据 本章将介绍为什么要学习大数据.如何学好大数据.如何快速转型大数据岗位.本项目实战课程的内容安排.本项目实战课程的前置内容介绍.开发环境介绍.同时为大家介绍项目 ...

  6. selenium打开Chrome浏览器并最大化

    #打开Chrome浏览器并放大 from selenium import webdriver def BrowserOpen(): driver = webdriver.Chrome(); drive ...

  7. 微服务杂谈--EureKa及自我保护

    时值初夏,各位老官的心也有所悸动,这不,众看官搬好小板凳,沏一壶清茶,待听Jerry话谈Eureka,以此静心.话不多少,且听: 一.微服务的产生 单体应用:一个jar或者一个war包交给运维,运行在 ...

  8. Calendar日历工具类

    这个工具类有效的避免跨年的问题 先定义一个日期格式类型: SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:s ...

  9. OPPO F9 Pro在哪里打开usb调试模式的完美方法

    经常我们使用pc通过数据线连接到安卓手机的时候,如果手机没有开启USB调试模式,pc则没能够成功读到我们的手机,此情况我们需要找处理方法将手机的USB调试模式开启,今天我们介绍OPPO F9 Pro如 ...

  10. SEH exception with code 0xc0000005 thrown in the test body

    在用Visual Studio时遇到这个报错.原因:访问了非法的内存地址. 这个问题不应该被忽略,通常是代码有bug. 解决办法: VS2013: 菜单->Debug->Exception ...