菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
241
0

OO第二单元--多线程电梯

原创
05/13 14:22
阅读数 29472

一、设计策略

(1)单电梯:

  a、线程分工:

    elevator、request两个线程。

      elevator线程主要负责乘客的接送和进出。

      request线程是接收乘客信息。

    control是缓冲器,用来保存elevator和request两个线程共享的乘客队列。

  b、调度策略:

    以电梯当前楼层和运行状态为基准,如果电梯是上行的,并且高于当前楼层还有乘客要进出就上行,否则判断是否低于该楼层有需求,如果有就下行。反之亦然,若是没有需求,则令电梯停止。对于乘客的调度则是到了规定楼层,能出则出,能进则进。

(2)多电梯1.0:

  a、线程分工:

    elevator类的五个电梯线程以及request线程。

    elevator线程主要负责乘客的接送和进出。

    request线程是接收乘客信息。

    control是缓冲器,用来保存elevator和request两个线程共享的乘客队列。

 

  b、调度策略:

    基于第一次作业的单电梯,将request中获得的乘客,平分到每个电梯中。

(3)多电梯2.0:

  a、线程分工:

    elevator类的若干个线程以及request线程。

    elevator线程主要负责乘客的接送和进出。

    request线程是接收乘客信息。

    control是缓冲器,用来保存elevator和request两个线程共享的乘客队列,以及保存电梯类的个数。

  b、调度策略:

    扩展PersonRequest类的功能,便于进行换乘操作。根据ABC不同的电梯停靠楼层对接收的乘客进行分类。能够直达的尽量直达,若是出现都能直达的情况根据ABC的优先级进行分类。若是不能直达的,则根据出发楼层ABC进行分类,换乘楼层集中在固定楼层1、5、15,便于进行操作,减少开关门的时间损失。对于同类别的不同电梯的乘客调度同第二次作业,对于电梯的运行同第一次作业。

二、第三次作业的可扩展性(SOLID原则)

(1)SRP(单一职责)原则

   request类主要进行生产者线程,elevator进行电梯的主要功能,control进行乘客信息的调度以及保存。三类的功能都不相同,符合单一职责的原则。在control中虽然有很多的方法,但是执行的目的都是十分简单,还是符单一职责原则。

(2)OCP(开放封闭)原则

   因为没有在写作业时,没有考虑代码的可扩展性,很多方法在第三次多电梯的实现中,进行了些许的调整,如果该电梯还要进行一些扩展操作,我想对于这些方法还是应该要进行调整。因此我觉得第三次作业的OCP原则还是不是很好。

(3)LSP(替换)原则

   第三次作业中我单独写了三个电梯类,没有归类到一个父类里面,因为在创建类,以及执行过程中都是用的电梯序号,所以没有这方面的问题。

(4)ISP(接口隔离)原则

    对于不同电梯,通过电梯索引来对电梯进行操作,在后续的几次拓展都得到一个很好的实现,所以相对来说接口隔离实现得比较好。但是对于电梯没有通过属性规范,而是独立的建立了三个电梯类,我觉得这一方面的接口原则就处理得不是很好。

(5)DIP(依赖倒置)原则

   control缓冲区元素的建立依赖request的运行,elevator的执行和建立依赖control,没有出现循环依赖的情况,还是很好的满足了依赖倒置的情况。

三、度量分析

 

(1)第一次作业:

    UML

 

 

 

    复杂度分析

 

    a、dependency

 

 

 

 

    b、 complexity

 

    总结

 

     复杂度较好,但是对于control的setUpFloor方法的复杂度就比较高,这跟我的调度策略有着很大的关系,四次用到循环,结果作为条件的一种嵌套,都增加了复杂度,而这些在后续几次作业都有体现。

 

(2)第二次作业:

    UML

    复杂度分析

    a、dependency

    b、 complexity

 

 

    总结

     这一次作业的的独立性相对比较好,但是复杂度分析有很多的方法爆红,特别是setUpFloor的方法,我想应该是在该方法有四个循环,导致该方法的复杂度很高,而且得出的结果又会用来下一次的判断条件,所以有一个嵌套的复杂度,但是关于该方法的修正没有比较好的想法。

(3)第三次作业:

    UML

 

 

 

    复杂度分析

    a、dependency

 

 

 

    b、 complexity

    总结

     这次作业的依赖性除了MainClass因为需要其他类来辅助执行,所以相对来说大一点其他还好。复杂度分析图中,相比于第二次作业,爆红的方法又加了一个addRequest方法,因为这次作业的调度设计涉及指定楼层,在没有找到一个统一的方法的时候,只能通过打表的方式进行调度,我觉得或许可以通过将该函数进一步细化,得到一个复杂度较好的函数。

(4)plantMUL

 

 

 

四、bug分析

(1)自我bug分析

    互测测到的bug主要是错误使用了notify,随机的唤醒线程使得我一些线程长睡不醒,改成notifyAll后就不会出现这样的随机性了。

   值得一提的是第三次作业的中测,由于对于notifyAll、wait的理解不够深入,导致我在关于wait对象一判断就唤醒,出现了一些线程wait条件判断被阻塞,导致测试RE差点死于中测。但是经过这一次我好好学习了notifyAll的使用,发现只有在wait对象状态发生改变的时候,即true变成false,才能够notifyAll

(2)hack的bug

    第一次作业hack到的是暴力轮询的bug;第二次作业没有hack到;第三次作业hack到的是RE的bug,我觉得应该就是我中测碰到的那个类型的bug。

五、bug策略

   这次hack构造,主要从很长时间再来一个人hack暴力轮询,通过一次来很多人hack调度分配线程冲突。但是碰到一些评测到无法复现的bug还是感到多线程就是运气的问题,但是如果一个安全的程序不应该依赖于运气,应该要有一个充分的维护。与第一单元相比,这一次的作业在调试,bug复现的难度上大大的提高,而且有时候原理搞不明白,也很难找到bug。所以我认为还是应该要细细的分析程序,通过自动测试的方式只能是一种手段,还应该从从线程的程度上考虑,避免阻塞的情况发生。

六、心得体会

   在这一次作业中,从线程安全上考虑应该要理清楚线程的执行顺序,线程共享的对象。设计原则上应该尽可能的符合开闭原则,减少一些重复操作和闭合操作,防止死锁的产生。多线程的体验中,我学习到了一些设计模式,虽然理解还不是很透,但是对于多线程的协作感到十分的神奇,而且感觉十分的接近现实生活。而且感觉学习写程序,不应该依赖于专有的设计架构,应该多想想多尝试一些原理。不然再后续调bug,可能自己就算是小黄鸭讲解程序,也还是不会找到程序的bug。同时这种多线程的使用,在过程式代码中是相当难实现得,又进一步了解了面向对象程序!

 

发表评论

0/200
241 点赞
0 评论
收藏
为你推荐 换一批