面向对象第二单元(多线程调度)总结体会

面向对象第二单元(多线程调度)总结体会

前言

​ 这三次作业的训练目的在于熟练掌握JAVA多线程同步互斥调度。其采用了比较贴合实际的电梯问题来作为载体,将多线程调度由易到难分成三个部分:

第一阶段要求了解结合多线程概念,理解电梯与请求之间的协作关系,考虑哪些资源需要被两个进程同时访问

第二阶段要求不再是单方向的信息传递,而是两个方向的信息交互,尤其注意交换信息时的同步关系

第三阶段要求采用更加科学高效的调度算法,同时满足电梯与电梯之间的互斥,电梯与请求之间的同步

1.第五次作业(FAFS电梯模拟)

1.1 程序类图展示

面向对象第二单元(多线程调度)总结体会_第1张图片

1.2 程序结构分析

Mainclass为主类,通过创建RequestElevator两个线程来实现功能。

使用的是“生产者-消费者”模型,将请求队列存在queue 中,而RequestElevator一个向queue中加入请求,一个从queue中得到请求。

请求的加入: put(PersonRequest):

用来向ArrayList请求队列中添加一个请求,该函数使用synchronizedElevator进行互斥。

请求的取出: get():

用来从ArrayList请求队列中取出一个请求,若queue为空,则将Elevator进程设为阻塞态。该函数使用synchronizedRequest进行互斥。

请求的结束:setOver(Boolean):

Request进程死亡时,将over位设为true,同时唤醒可能在睡眠中的Elevator进程。该函数使用synchronizedElevator进行互斥。

1.3 优缺点分析

优点:此次作业比较完全地使用了生产者-消费者模式,而没有将调度放在电梯当中。类之间的耦合度较低,通过JAVA自带的synchronized实现了进程之间的互斥,完成了信息的共享与交换。

缺点:没有在此基础上使用更高级的调度算法,而无法实现人员的捎带。程序实现的是实打实的FAFS模式

1.4 设计原则检测

  • Single Responsibility Principle:类/方法的功能行为单一,电梯仅根据需求执行上下功能,符合该原则。
  • Open Close Principle:一定程度上考虑了可拓展性,但依照开闭原则应该进一步增加框架弹性。
  • Liscov Substitution Principle:无子类无继承,满足里氏替换原则。
  • Interface Segregation Principle:无接口设计,满足接口分离原则。
  • Dependency Inversion Principle:调度器(高层模块)不依赖于电梯(低层模块)的行为,符合该原则。

1.5 代码度量

复杂度分析

面向对象第二单元(多线程调度)总结体会_第2张图片

依赖度分析

面向对象第二单元(多线程调度)总结体会_第3张图片

本次代码的整体复杂度较低,代码规模较小,依赖度也没有超过2。整体代码量只有100+行,实现模式较为简易。

1.6 UML协作图

面向对象第二单元(多线程调度)总结体会_第4张图片

1.7 Bug分析

第一次程序所在房间内均为满分。既没有被找到bug,也没有找到别人bug

通过读同房间其他同学的代码,发现由于指导书要求较为明确,观察到许多同学的思路基本相同

最大的区别在于是否将控制器作为一个线程运行。

若不作为一个线程,则是标准的生产者-消费者模式;若作为一个线程,则类似于观察者模式。

2.第六次作业(单部可捎带调度(ALS)电梯)

2.1 程序类图展示

2.2 程序结构分析

从类图可以看出,第二次程序类图与第一次大体不变,主要的改动为:

  • Controller中加入了getMainNeed()方法
  • Elevator中加入了mainNeedisOpenDoor变量,并定义了相关的getter and setter方法

当电梯内没有人时,访问Controller来取得主请求;当电梯在运行时,每到一层先遍历电梯中的所有人员,观察是否需要开门出去,之后更新主请求;然后访问Controller来了解是否需要上人,再次更新主请求。最后根据主请求上行或者下行。

2.3 优缺点分析

优点:在上次的基础上复用了较多的代码,证明整个框架的设计比较合理,且可以按照指导书的要求进行运行。

缺点:本次仅仅实现了AFS调度,而没有想到更高效的方案,使得性能分部分爆炸;在负一层与一层之间转移时使用了特判,导致之后第三次作业还需重新构思相关设计。

2.4 设计原则检测

  • Single Responsibility Principle:电梯仅根据需求执行上下功能,而采用询问的方法获得主请求,符合该原则。
  • Open Close Principle:一定程度上考虑了可拓展性,但在楼层转移上没有考虑复用而偷懒特判,需要反思。
  • Liscov Substitution Principle:无子类无继承,满足里氏替换原则。
  • Interface Segregation Principle:无接口设计,满足接口分离原则。
  • Dependency Inversion Principle:控制器(高层模块)的调度依赖于电梯(低层模块)的行为,不符合该原则。

2.5 代码度量

复杂度分析

1615411-20190424183917579-1421798934.png

依赖度分析

面向对象第二单元(多线程调度)总结体会_第5张图片

复杂度分析中,两个最重要的方法复杂度明显大于其他方法,由于首先需要将queue遍历一遍,并在其中判断,在循环中还要将不同的情况分类讨论,故需要多个if语句,所以整体复杂度要高于其他方法。而依赖度关系情况良好,类与类之间的依赖度关系比较稳定。

2.6 UML协作图

面向对象第二单元(多线程调度)总结体会_第6张图片

2.7 Bug分析

此次作业强测没有被找到bug,同时也没有找到他人bug。虽然性能分近乎爆炸,但可靠性得到了保障。测试他人bug的时候,使用Random类与正则表达式随机生成了一些数据,并利用.sh文件与管道实现了自动化评测,但各个同学的调度算法均不同,无法通过肉眼观察是否输出内容是否正确,只能通过观察是否超时来计算。但由于效率比较低下,并没有在有限的时间内找到有效的bug提交。

3 第七次作业 (多部智能(SS)调度电梯)

3.1 程序类图展示

面向对象第二单元(多线程调度)总结体会_第7张图片

3.2 程序结构分析

从程序类图可以发现,本次结构与上次最大的不同即为加入了一个新的Scheduler类来完成调度任务。而输入接口接入的不再是Controller,而是Scheduler。而Controller变成了每台电梯的附属控制器,用于管理控制已经分配给每台电梯管理请求的捎带。具体的调度策略如下所示:

  • Scheduler通过判断请求是否可以由一部电梯独立完成,若可以则按照空闲>A>B>C的策略分配电梯
  • 若无法通过一部电梯到达目的地,则将请求拆分为两个,而中间的过渡楼层的判断以“运行速度快的电梯多运行,运行速度慢的电梯少运行”的原则进行选择。然后将请求的第一部分按照上一步的原则分配电梯,将请求的第二部分存在SchedulerHashmap中,并用PersonRequestid作为Key
  • 控制器将调度器给它的请求存入自己的queue,并按照上次作业的算法进行电梯的捎带请求。唯一改变的是,当电梯人数已满的情况下,不进行人员进入的操作。

3.3 优缺点分析

优点:在每台电梯的内部调度部分几乎复用了所有代码,证明该框架的复用性良好;使用比较高效的静态调度算法,而由于感觉动态调度算法会破坏“高内聚,低耦合”的原则,而没有考虑使用。

缺点:在代码中有些数据可以GET INSTANCE方式来调取使用,但却使用了调取Elevator类中的私有类变量,提高了类与类之间的耦合度关系。在判定换乘时,按照最多换乘一次的方法进行设计的,而没有采用图论的最短路径算法,这样使得代码的复用性极差,若有下次作业,Scheduler中的调度或许需要完全重构。

3.4 设计原则检测

  • Single Responsibility Principle:调度器计算拆分需求并交给电梯控制器,电梯仅根据需求执行上下功能,而采用询问的方法获得主请求,符合该原则。
  • Open Close Principle:在电梯的换乘中没有按照构造图的普适方式实现,而使用了换乘一次的方法,需要反思。
  • Liscov Substitution Principle:无子类无继承,满足里氏替换原则。
  • Interface Segregation Principle:无接口设计,满足接口分离原则。
  • Dependency Inversion Principle:调度器,控制器(高层模块)的调度依赖于电梯(低层模块)的行为,不符合该原则。

3.5 代码度量

复杂度分析

面向对象第二单元(多线程调度)总结体会_第8张图片

面向对象第二单元(多线程调度)总结体会_第9张图片

依赖度分析

面向对象第二单元(多线程调度)总结体会_第10张图片

可以观察到,本次代码中复杂度较高的函数除了上次作业中的getgetMainNeed,还有调度器中的isSingle(单电梯调度)和isDouble(双电梯调度),与预料中的基本相似。而依赖度关系的上升,很大程度上是由于在数据选择上采取使用Elevator中的数据,而没有GET INSTANCE,需要反思。

3.6 UML协作图

面向对象第二单元(多线程调度)总结体会_第11张图片

3.7 Bug修复

本次强测还是没有被找到bug,也没有找到别人bug。强测的性能分较上次而言,有所提高。在寻找他人bug的时候,考虑到同房间同学的分数与我相近,仅采用了暴力测试,观察程序是否超时这一方式,而没有采用更加明智的方法。

总结

本三次作业在很大程度上使我理解了JAVA多线程编程的特点,对线程之间的同步互斥关系有了更深入的认识。在代码复用上,对比较第一次作业而言进步巨大,基本上后一次作业对前一次作业达到80%以上的复用,但在多线程调试以及测试bug中还没有做到自动化测试的效果,期待在后续的时间中,通过自学和老师的帮助,可以对多进程的其他编程思想以及测试有更高层次的理解。期待下一单元的OO练习ing!

转载于:https://www.cnblogs.com/ArthurN/p/10764089.html

你可能感兴趣的:(面向对象第二单元(多线程调度)总结体会)