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

设计策略

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

    一 介绍 二 安装 三 基本使用 四 选择器 五 等待元素被夹在 元素交互操作 其他 项目联 一 介绍 selenium最初是一个自动化测试的工具,而爬虫中使用它主要是为了解决requests无法直接 ...

  2. 07binlog日志介绍

    设置日志格式为row 创建数据库和表 mysql> create database chinasoft charset=utf8mb4; mysql> use chinasoft; mys ...

  3. springboo+nginx测试反向代理01

    操作环境:centos7,springboot2.1,nginx1.8.1 boot程序链接地址 : https://github.com/zgq7/nginxDemo nginx下载地址: http ...

  4. 面向对象之组合VS继承:继承过时了?

        在阅读Effective Java中的第16条时发现了一个有趣的机制或者说是模式,那就是组合(文中翻译为复用,但是作者认为组合更能体现这种模式的精神),并且文中建议使用组合.  那什么是组合, ...

  5. 洛谷P4770 [NOI2018]你的名字 [后缀自动机,线段树合并]

    传送门 思路 按照套路,直接上后缀自动机. 部分分:\(l=1,r=|S|\) 首先把\(S\)和\(T\)的后缀自动机都建出来. 考虑枚举\(T\)中的右端点\(r\),查询以\(r\)结尾的串最长 ...

  6. 重磅发布:阿里 OpenJDK终于开源啦! 将长期支持版本 Dragonwell

    前几天的北京阿里云峰会,阿里巴巴正式宣布对外开源 OpenJDK 长期支持版本 Alibaba Dragonwell.作为 Java 全球管理组织 Java Community Process (JC ...

  7. python读取uti-8格式ini配置文件出现UnicodeDecodeError: 'gbk' codec can't decode byte 0xba in position 367: illegal multibyte sequence错误解决方法

    出现这种错误只需要在read下添加encoding='utf-8' 如: from configparser import ConfigParser cf = ConfigParser() cf.re ...

  8. 集腋成裘-13-git使用-02进阶篇

    上一篇我们简单介绍了如何安装和使用git,本次将简单介绍如何创建分支.处理冲突.提交与回滚 创建和合并分支是Git的一大特色. 使用场景:当有一个新功能要开发,但是又没有确定上线时间,不能合并到主干上 ...

  9. 大数据学习之HDFS基本API操作(下)06

    hdfs文件流操作方法一: package it.dawn.HDFSPra; import java.io.BufferedReader; import java.io.FileInputStream ...

  10. symfony简单的博客练习,熟悉具体开发流程

    这里搭建一个简单的博客系统作为练习,之后再完成学校任务搭建一个表白墙, 使用htmlpurifier和parsedown来搭建前端,所以需要先安装这两个第三方包,必须要弄一个composer的国内镜像 ...