概述:

  面向对象的第二单元是多线程电梯。第一次实现一部傻瓜电梯,每次只送一个人;第二次实现一部可稍带电梯;第三次实现三部可稍带电梯。

一、设计策略

1、第5、6次作业设计思路

第5、6次作业的架构相似,由一个电梯线程,一个读请求线程,一个调度器组成;电梯和读请求进程通过调度器交互。

读请求线程不断的从标准输入读入请求,将请求存放在调度器的队列中;

电梯线程从调度器中获取请求并执行。

调度器维护一个共享队列,用来存放请求。

读请求线程和电梯线程并发执行,二者对调度器中队列的操作保证互斥,同一时刻只有一个线程能够操作队列。

2、第7次作业设计思路

  三部电梯调度中,三个电梯线程和主线程同步执行,四者对于主调度器的写操作是互斥的,主调度器对副调度器的写和相应电梯线程对副调度器的读操作是互斥的。

二、程序结构分析

1、通过Designjava分析三次作业的类和类中的方法

图 1 第5次作业类和类中方法度量结果

图 2 第6次作业类和类中方法度量结果

图 3 第7次作业类和类中方法度量结果

  可以看到第5次作业RequestQueue类的LCOM值为正(其余都为0或负数),代表其内聚缺乏度高,该类中的函数逻辑相关性差,容易导致bug。

  分析发现第5和第6次的作业FANIN和FANOUT都为0,耦合度较差,第7次作业的FANIN和FANOUT值比较合理,可能原因是第3次作业将功能进行分类,每个功能都封装在一个包里,而前两次作业直接将class放在default package中。

  通过分析LOC方法的行数发现,除了几个逻辑复杂的方法之外,别的方法基本控制在30行以内,效果比较好。

2、三次作业的类图

图 4 第5次作业类图

图 5 第6次作业的类图

图 6 第7次作业类图

  第5次和第6次作业的逻辑差不多,只不过第5次作业单独一个线程来读取请求,第6次作业是在Main中读取请求,两次作业都是读请求线程和电梯线程通过一个调度器进行交互。第7次作业两层调度器,每个电梯绑定一个调度器,三部电梯统一建模,三个副调度器统一建模,逻辑清晰,不容易出错,但是基本没有考虑优化。

3、第7次作业协作图

图 7 第7次作业协作图

4、从SOLID五原则角度分析第7次作业的问题

4.1 SRP(每个类或方法都只有一个明确的职责)

  Elavator.java中的run函数代码长度将近60行,其中实现了太多的功能,容易出错,应该将其分解成几个方法,每个方法实现一项职责。

4.2 OCP(无需修改已有实现,而是通过扩展来增加新功能)

  第7次作业的电梯和副调度器跟第6次作业的很像,应该通过扩展来完成,而不是像我一样重构。

4.3 LSP(任何父类出现的地方都可以使用子类来代替,并不会导致使用相应类的程序出现错误。)

  ISP(当一个类实现一个接口类的时候,必须要实现接口类中的所有接口,否则就是抽象类,不能实例化出对象)

  DIP(高级模块不应依赖于低级模块。两者都应该依赖于抽象)

  本次作业没有涉及这三个点

三、分析自己程序的bug

  第5次作业中由于共享变量endFlag没有加锁,导致程序出错。这给我的经验教训是,多线程中一定要找出所有的共享变量,考虑每个共享变量的安全问题,多次反复执行复现bug。写的代码一定要逻辑清晰,否则绕来绕去的很容易出错。

四、心得体会

  通过第二单元的三次电梯作业,我了解了java的多线程实现方法和原理。总的来说三次作业的步骤大致如下:

1、首先要确定好哪些是线程,哪些不是线程,例如作业中的调度器是否将他设计为线程;

2、然后设计多线程的交互,通过什么方式,谁调用谁的方法;

3、要找到所有的共享变量,对存在安全隐患的共享变量加锁;

4、对于同一组测试数据要多次运行,确保无隐藏的bug。

  多线程利用好了可以提高资源利用率,而利用不好会导致死锁、结果出错等各种各样的bug。多线程很难通过构造全的测试数据来debug,只能通过确保架构无误,逻辑无误来实现正确性,这就要求我们在设计阶段多花时间,写出一个逻辑清晰,高内聚低耦合的程序。

OO_多线程电梯_单元总结的更多相关文章

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

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

  2. OO_Unit2 多线程电梯总结

    OO_Unit2 多线程电梯总结 相比于Unit1的表达式求导,Unit2的多线程电梯听上去似乎显得更加"高大上".但在完成了3个task的迭代后再回过头去比较这两个单元,我发现其 ...

  3. OO Unit2多线程电梯总结博客

    OO Unit2多线程电梯总结博客 传说中的电梯居然就这样写完了-撒花

  4. OO_JAVA_JML系列作业_单元总结

    OO_JAVA_JML系列作业_单元总结 (1)梳理JML语言的理论基础.应用工具链情况 简单梳理 以下三者是jml规格里的核心,对一个方法功能和属性的限制: requires子句:规定方法的前置条件 ...

  5. OO_JAVA_表达式求导_单元总结

    OO_JAVA_表达式求导_单元总结 这里引用个链接,是我写的另一份博客,讲的是设计层面的问题,下面主要是对自己代码的单元总结. 程序分析 (1)基于度量来分析自己的程序结构 第一次作业 程序结构大致 ...

  6. BUAA_OO第二单元总结性博客作业——多线程电梯架构

    一.设计策略 在第一次作业时,我刚第一次接触多线程这个东西……于是乎对于第一次VIP直上直下一次只接一个人的电梯,我借鉴了指导书中为我们提供的架构,设计了一个输入线程和一个电梯线程,并设置了一个中间类 ...

  7. 2019年北航OO第二单元(多线程电梯任务)总结

    一.三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程.这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以 ...

  8. OO_JAVA_电梯运行模拟_单元总结

    电梯运行模拟--三次作业总结 目录 电梯运行模拟--三次作业总结 总体遵循的设计思路 逻辑解耦 电梯与调度器解耦 楼层信息的存储和变更与电梯.调度器解耦 调度器运行流程解耦 第一次电梯,蠢笨串行先到先 ...

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

    第五次作业分析 1.设计策略 调度器采用单例模式,内部设请求队列,对请求队列的一切操作(查.增.删)都在调度器内完成,且都要求串行,从而确保线程安全.接收器和电梯是两个线程:接收器接受请求调用调度器来 ...

随机推荐

  1. Asp.NET 简易通用WebServices 附件服务

    [toc] 总述: 用了很久的附件分离服务, .NET 2.0平台开始使用.  配置好服务后, 由调用端定义并管理目录级次.  调用端存储目录即可.  附件服务: 相应配置节点放入 web.confi ...

  2. spark-rpc是如何实现将netty的Channel隐藏在inbox中的

    class TransportServer bootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Overri ...

  3. RF:win10跑用例过程中有中文日志会显示非中文

    问题:RobotFramework在win10跑用例过程中有中文日志会显示非中文,如截图: 解决:  C:\Python27\Lib\site-packages\robot\utils\unic.py ...

  4. 设计一函数,求整数区间[a,b]和[c,d]的交集

    问题: 设计一函数,求整数区间[a,b]和[c,d]的交集.(c/c++.Java.Javascript.C#.Python)  1.Python: def calcMixed(a,b,c,d): r ...

  5. hbase概述和安装

    前言 前几天刚学了Hadoop的安装,几乎把Hadoop的雷都踩了一个遍,虽然Hadoop的相关的配置文件以及原理还没有完全完成,但是现在先总结分享一下笔者因为需要所整理的一些关于Hbase的东西. ...

  6. 关于Qrc文件的用法

    在python文件xxx.py中调用资源文件,一般来说,需要将资源放在xxx.py的相同目录下:然而,当在xxx.py下建立一个统一目录/rec则需要建立xxx.qrc文件才能让xxx.py调用,调用 ...

  7. Java中的char占用几个字节

    目录 1.概述 2.答疑 3.总结 1.概述 网上或书上都说是Java中的char占用2个字节,一直没有深入,直到接触了编码,才对此产生了疑问,今天来深入一下这个问题. 2.答疑 char在设计之初的 ...

  8. TIMESTAMP类型字段在SQL Server和MySQL中的含义和使用

    公众号上转的满天飞的一篇文章,MySQL优化相关的,无意中瞄到一句“尽量使用TIMESTAMP而非DATETIME”,之前对TIMESTAMP也不太熟悉,很少使用,于是查了一下两者的区别. 其实,不管 ...

  9. python 随机生成图片验证码背景RGB-浅色或者深色

    import random def random_color(is_light = True): return (random.randint(0 ,127) + int(is_light) * 12 ...

  10. make,makefile,cmake“暴力编译法”的个人经验或理解。

    通常我们在本地编译库(opecv.pcl)等我们喜欢使用make -jN  (N代表线程数)这样可以加速编译过程, 但是,这不一定是“线程安全”的,因为当某个线程在编译时,经常其他线程编译依赖本线程的 ...