OOP第二次博客作业

(1)从多线程的协同和同步控制方面,分析和总结自己三次作业的设计策略

在三次作业中,我都采用了通过一个共享队列,采用轮询(非暴力轮询)的方法进行信息的传递,在初次接触多线程时,由于害怕产生死锁,故最初采用了这样的方法,但这样的信息交互方法,相对于普通生产者消费者模型的wait()notify()方法肯定效率较低,有许多无用的查询,在以后的练习中,还是需要改成wait()notify()

在考虑同步控制的方法时,我是采用syncronized修饰临界区的方法来进行防止多个线程同时对一个临界资源进行操作。在刚接触多线程时,我记得最清楚的点就是ArrayList是线程不安全的,Vector是线程安全的。由于对于这一区别的不了解,我就在电梯第二次作业中,将所有的ArrayList都替换成了Vector,想以此来保证多线程的安全性。在后来自己的测试和资料的查阅中,我发现Vector的线程安全体现在其方法的原子性,但在符合操作中还是得使用锁的方法进行互斥访问,所以在这里ArrayListVector并没有差别。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

在第一次作业,由于没有性能分,就直接照搬傻瓜调度的方法进行程序的构建。

在第二次作业,采用(伪)Look算法进行调度,但是由于自己的设计失误使得自己做了一个零优化。(在电梯进行调度接人时,例如电梯上行接一个要下行的人,我会将请求指令派发给电梯,却没有电梯的调度中增加目的楼层的刷新和检测楼层是否有人需要进出,也就导致了增加的优化毫无意义)

第三次作业,我沿用第二次的架构,调度器先静态拆分不可直达的指令,再通过请求的优先级(例如-3-3优先级最高)来派发指令

while (true) {
           /*to split the personRequest*/
           checkSplit();
           for (int i = 1;i <= 3;i++) {
               upDispatch(i);
          }
           for (int i = 1;i <= 3;i++) {
               downDispatch(i);
          }
           if (waitList.isEmpty() && upList.isEmpty() &&
                   downList.isEmpty() && inputFlag.getFlag()) {
               managerFlag.setFlag();
               break;
          }
           Main.sleep(breakTime);
}

同时根据电梯的运行状况选择运送时间最短的电梯进行运送。

private ConcreteElevator chooseBestE(PersonRequest personRequest) {
       long leastTime = 50000;//the max time
       ConcreteElevator bestE = elevators[0];
       for (ConcreteElevator concreteElevator : elevators) {
           if (concreteElevator.isCarry(personRequest, isBypass)) {
               long time = concreteElevator.costTime(personRequest, isBypass);
               if (leastTime >= time) {
                   bestE = concreteElevator;
                   leastTime = time;
              }
          }
      }
       return bestE;
  }

由于第二次作业问题没有发现,导致了我在第三次作业的负优化。(由于一个指令派发给某一个电梯,但是由于他没有捎带走,只能等他运行完其他指令才能运送这一指令,造成了很大的性能损失)

(2)基于度量来分析自己的程序架构

三次作业的类图如下所示:

OOP第二次作业 随笔 第1张

 

OOP第二次作业 随笔 第2张

OOP第二次作业 随笔 第3张

OOP第二次作业 随笔 第4张

OOP第二次作业 随笔 第5张

本次作业较为简单,未发现什么问题

OOP第二次作业 随笔 第6张

 

OOP第二次作业 随笔 第7张

 

OOP第二次作业 随笔 第8张

OOP第二次作业 随笔 第9张

 

 OOP第二次作业 随笔 第10张

OOP第二次作业 随笔 第11张

 

和第三次作业大体一致,在第三次作业中详述

OOP第二次作业 随笔 第12张

 

OOP第二次作业 随笔 第13张

 OOP第二次作业 随笔 第14张

 OOP第二次作业 随笔 第15张

OOP第二次作业 随笔 第16张

OOP第二次作业 随笔 第17张

 OOP第二次作业 随笔 第18张

在第三次作业中,主要的问题还是电梯过于复杂,由于我分配请求是根据当前情况下哪一个电梯运送这个请求最快来指派电梯,所以需要计算cost,为了减轻代码量就把这一部分放在了电梯中泽娜加了电梯的复杂度,这一部分内容本应该全部有调度器负责。解耦合情况我认为也还可以。

 

整体类的分配我觉得还是较为合理的,没有出现类的职责严重混淆起来的情况。

优点:在计算时间时,将部分实现代码放在了电梯中,减少了整体的代码量

缺点:在计算时间时,将部分实现代码放在了电梯中,增加了电梯和调度器之间的耦合,不利于类与类职责的拆分

 

基于SOLID原则的分析:
Single Responsibility Principle:基本遵循,除了在上面写的计算时间时导致了电梯多承担了一部分功能
Open Close Principle:没有很好的实现,在进行功能的添加时,会对一些模块进行修改,说明在最初进行架构设计时并没有很好的考虑接下来的可能需求,以后需要多对于此进行分析,在设计一个好的架构,能够实现对扩展开放、对修改关闭
Liskov Substitution Principle:没有体现,由于在这三次作业中都没有用到继承,所以没有涉及。
Interface Segregation Principle:没有体现,在这三次作业中没有出现多个类共享一个接口的情况,所以没有涉及。
Dependency Inversion Principle:在第三次作业中,限制了每个电梯所能到达的楼层,但在之前我并没有预估到这一情况的发生,所以将这一属性内嵌在了电梯的实现中,在之后的作业中,一定要好好的分析需求,使得方法依赖于抽象而不是具体实例。

(3)分析自己程序的bug

第一次和第二次作业在公测和互测中没有bug。

在第三次作业中由于一些事情,太迟进行代码的编写,导致对于代码的测试不足,一个小小的疏漏公测出了一个bug。

for (int i = 1;i <= 3;i++) {
upDispatch(i);
}
for (int i = 1;i < 3;i++) {
downDispatch(i);
}
//漏了一个=,导致调度器一直有一个15-1的人无法派分出去,导致了程序的不能结束。

由于对于多线程有了大概清晰的了解,并且采用轮询的方法,没有出现多线程相关的蜜汁bug

(4)分析自己发现别人bug所采用的策略

我采用python生成随机数据,再使用管道实现不断喂数据给程序,再对结果进行正确性检测。在测试别人的程序时,使用随机数据进行测试,测出了4,5个bug,效果还是不错的,在第二次作业时,由于知道有同学被发现了bug,所以针对其代码结构编写了测试样例,找到了一个bug。其他全部采用随机测试的方法,将错误同学的输入复制到其文件夹中,以随机字符串给其命名以防止覆盖。

(5)心得体会

1:不能使用基本数据类型作为共享对象,最初使用Boolean来作为共享对象,后来发现这不是引用传递,而是值传递,导致程序不能正常结束。

2:Vector的安全性只体现在其方法的原子性上,在复合操作中不保证原子性。

3:考虑在需要用视有多个读者的时候使用读写锁才来提高多线程对于数据访问的效率。

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄