一、三次作业的设计策略

  (1). 第五次作业

    第五次作业由于较为简单,在强测及互测中均没有出现BUG,但是并没有做优化。本次的设计有些不合理,所以在后面的作业中也做了重构。本次的作业主要有三个类,主函数类,指令类,和电梯类。其中主函数中完成输入的操作,并且每获得一条指令就开启一个指令线程(严重不合理之处,自己当时理解错误),指令类中的run方法是每次开始就wait,直到电梯送完一个人才会notifyall,唤醒所有指令线程,如果有一个指令能够进入电梯,则运行电梯,其他指令线程继续wait。这种设计在后来进行了修改。在后来我也发现了这种开多个线程的写法性能十分低下。

  (2). 第六次作业

    第六次作业我认为较为困难。开始时的设计是一共有电梯,调度器和电梯三个线程,但是在调度器和电梯之间是通过电梯每到达一层就会notify调度器,由调度器将等待队列中的,能够上电梯的乘客放入电梯的乘客队列,然后notify电梯,让电梯启动。但是这种设计实际上存在问题,由于自己当时对锁的理解并不深入,后来才发现这种相互notify的设计线程不安全,会有电梯还没来的及进入wait,调度器就已经notify电梯了,造成电梯真正进入wait状态时无法被唤醒,造成错误。(这也是我无效作业的原因)。后来将调度器改为每次遍历完当前等待队列,将人塞入电梯后就wait,直到电梯到达某一层,并且状态是wait的时候才会进入下一次遍历。这种设计通过了强测,也让我对线程的锁理解更加的深入。

  (3). 第七次作业

    第七次作业我一开始的想法有些复杂。开始时试图沿用上一次的策略,电梯每到一层,由调度器将能够上电梯的人塞入电梯,但是这次由于有三种电梯,且如果这样写的话换乘电梯较为复杂,所以最后并没有成功实现。后来的想法是,有三个电梯线程,一个调度器线程,一个输入线程。电梯负责将本电梯的等待队列捎带进入电梯,调度器负责将能直达的指令塞给电梯的等待队列,将无法直达的指令通过计算出两层间能够从哪层换乘其他电梯来拆分指令,并分为两部分塞入电梯和存入乘客类的副指令中,在人出电梯时才将副指令加入指令队列中。这种调度虽然无法让其他电梯在能够接人时提前过去,但是在最大限度上保证了线程安全,最后在强测及互测中正确性表现良好。

二、基于度量分析自己的程序结构

  (1). 第五次作业

   类图:

         

   时序图:

     

        算法主要是:

          • 主函数负责输入,并将输入的request new 一个Intruction对象并线程开启。
          • Instruction类中传入了Elevator对象,通过调用Elevator的方法实现控制电梯;run方法主要先判断如果电梯在被使用则继续wait。否则抢电梯,运行电梯,最后notifyall,唤醒     在等待中的指令线程。
          • Elevator类中主要有电梯的上下行,去用户所在楼层,开关门的方法。

    复杂度分析:

      

      

    总体可见,复杂度还是可以的。但是算法存在明显缺陷。这种算法虽然在第二次作业中并没有复用,但是可想而知开很多线程开销会很大。实际上可以写成第二次的电梯的算法。

    根据SOLID原则,类的职责较为单一;只有继承Thread类;虽然没有使用接口类但是本次作业似乎并没有必要实现接口;满足最少知道原则,各类只public必要的方法;满足开闭原则。 

  (2). 第六次作业

    类图:

      

    时序图:

      

      算法:

      • 主函数负责开启3个线程,Elevator,Instructor ,Input
      • Input线程主要负责输入,将输入的request改为Passenger对象,并存入Instructor调度器对象中。(在输入截至时会notify在等待的线程,以满足平稳结束程序)。
      • Instructor线程负责将传入的指令中能够进入电梯的指令(电梯为空;或from与当前楼层一致,且与电梯当前运行方向一致)放入电梯的乘客队列。
      • Elevator线程负责上下行,开关门的工作,但每到一层,会wait,等待调度器(Instructor)将能够捎带的指令加入电梯后再运行。

    复杂度分析:

        

        

     总体可见本次设计中复杂度控制的并不很好。Elevator的run方法和Instructor的run方法都较复杂。

       根据SOLID原则,类的职责较为单一;只有继承Thread类;没有使用接口类;满足最少知道原则,各类只public必要的方法;开闭原则没有很好的满足(在结束时为了满足通知电梯停止而修改了电梯内部的标志,除了这种方法暂时还没有想到较为合适的通讯方法)。

  (3). 第七次作业

    类图:

      

    时序图:

      

       算法:

        • 主函数类主要用于开启5个线程,Input线程,Controller线程,和3个Elevator线程。
        • Passenger类保存了指令的信息以及无法直达指令的被拆分出来的第二条指令。
        • Input线程用于将输入的request转为passenger类并存入Requests类中的总队列中。
        • Controller线程首先遍历总队列,将可以直达的指令放入相应电梯的等待队列中,然后将无法直达的指令拆为两部分(根据矩阵,打表得来的),前半部分(有from及表中的to)作为可直达指令存入相应电梯的等待队列中,后半部分(表中的to和真实的to)存在乘客的sub中。
        • Elevator线程负责将本电梯的等待队列中的人按照ALS算法送达目的地。在乘客到达目的地时,判断下此乘客的sub是否为空,为空则直接出电梯,否则将此乘客的sub指令存入Requests的总队列中。     

    复杂度分析:

      

        

     总体可见本次设计中复杂度控制的并不很好。Elevator的run方法和Instructor的run方法都较复杂。

       根据SOLID原则,本次类的职责没有完全单一(Elevator类在实现工作职责的同时还实现了捎带,实际应该使用第二级调度器,但是为了保证线程安全并没有实现);只有继承Thread类;没有使用接口类;满足最少知道原则,各类只public必要的方法;开闭原则没有很好的满足(在结束时为了满足通知电梯停止而修改了电梯内部及调度器内部的标志)。

三、分析自己的BUG

  (1). 第五次作业

    本次作业由于较为简单并未发现BUG

  (2). 第六次作业

    本次作业开始时的写法存在调度器与电梯相互notify的写法,这种方法我发现是线程不安全的,很容易出现一个线程还没有来得及进入wait状态就被notify了,而notify只会执行一次,就导致无法被正常唤醒(加标志位也会存在类似的问题);后来的方法自己在测试时发现是使用synchronized时加错了锁,锁的是elevator对象而不是整个run方法导致最后没有改对。

  (3). 第七次作业

    第七次作业并未被发现BUG,自己测试时的BUG主要是轮询造成的。

四、发现别人BUG采用的策略

  主要通过精心构造数据,并使用按键精灵输入;在各种时刻ctrl + D以判断能否正常退出;还有为了能够精准在0秒输入,使用先使主线程sleep5秒后再输入,这样能够避免输入的误差(学习自讨论区)。第二单元的测试与第一单元的差异主要是第二单元为多线程问题,有些线程安全问题复现一次难度较大(就如第六次作业开始时相互notify这种写法,运气好时结果时正确的)。而且有些样例需要定时输入。

五、心得体会

  第一次接触多线程,由于自己初期的理解错误造成了第六次作业翻车。但这也使我对synchronized的使用有了更深的理解,比如synchronized锁的是括号中的对象,也可以锁当前对象,notify的则是拥有当前锁的对象。在实验课中学习到,若要实现两个进程间相互notify,可以为两个进程传入相同的Object对象,然后再锁这个对象即可,解锁时同理。第六次作业翻车可能的原因还有自己的心态问题,改到周二晚些时候有些着急。第七次作业实际上也经历了重构,但是基本在两个小时内就完成了重构(还将原来只有上下行等功能的电梯重构为了能够捎带的电梯。。。),希望以后能够更好的调整自己的心态,完全理解好之后再动手写代码。

OO-第二单元总结的更多相关文章

  1. oo第二单元作业总结

    oo第二单元博客总结 在第一单元求导结束后,迎来了第二单元的多线程电梯的问题,在本单元前两次作业中个人主要应用两个线程,采用“生产者-消费者”模式和共享数据变量的方式解决问题.在第三次作业中加入多个电 ...

  2. OO第二单元优化博客

    OO第二单元优化博客 第五次作业没有性能分,但是,我在这一单元的宗旨就是写一个日常生活中 最常见的那种电梯,所以第五次我没有写傻瓜电梯,而是直接写了个\(look\),和第六次基本相同. 总计一下lo ...

  3. 【OO学习】OO第二单元作业总结

    OO第二单元作业总结 在第二单元作业中,我们通过多线程的手段实现了电梯调度,前两次作业是单电梯调度,第三次作业是多电梯调度.这个单元中的性能分要求是完成所有请求的时间最短,因此在简单实现电梯调度的基础 ...

  4. OO第二单元小结

    OO第二单元小结 一.三次作业代码分析. 1.第一次作业 第一次作业是单部电梯的傻瓜调度,由于其过分傻瓜,所以第一次作业我只有两个类,一个main,一个电梯,main类负责不断从输入流中读取命令,如果 ...

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

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

  6. 电梯也能无为而治——oo第二单元作业总结

    oo第二单元作业总结 一.设计策略与质量分析 第一次作业 设计策略 在第一次作业之前,我首先确定了生产者--消费者模式的大体架构,即由输入线程(可与主线程合并)充当生产者,电梯线程充当消费者,二者不直 ...

  7. 2020北航OO第二单元总结

    2020北航OO第二单元总结 前言 本单元考察基于多线程的电梯调度问题,成功让我从一个多线程小白到了基本掌握了使用锁来控制线程安全的能力,收获颇多(充分体验了迷茫地de一个又一个死锁bug的痛苦). ...

  8. OO第二单元——多线程(电梯)

    OO第二单元--多线程(电梯) 综述 第二单元的三次联系作业都写电梯,要求逐步提高,对于多线程的掌握也进一步加深.本次作业全部都给出了输入输出文件,也就避免了正则表达式判断输入输出是否合法的问题. 第 ...

  9. OO第二单元作业总结【自我反思与审视】

    第二单元作业的完成史,就是一部心酸的血泪史…… 多线程的出现为我(们)打开一片广阔的天地,我也在这方天地摸爬滚打,不断成长!如果说第一单元之前还对Java语法有所了解的话,那么这单元学习多线程则完全是 ...

  10. OO第二单元(电梯)单元总结

    OO第一单元(求导)单元总结 这是我们OO课程的第二个单元,这个单元的主要目的是让我们熟悉理解和掌握多线程的思想和方法.这个单元以电梯为主题,从一开始的最简单的单部傻瓜调度(FAFS)电梯到最后的多部 ...

随机推荐

  1. 理解JS深拷贝

    前言: JS的拷贝(copy),之所以分为深浅两种形式,是因为JS变量的类型存在premitive(字面量)与reference(引用)两种区别.当然,大多数编程语言都存在这种特性. 众所周知,内存包 ...

  2. mysql杯观锁与乐观锁

    悲观锁与乐观锁是两种常见的资源并发锁设计思路,也是并发编程中一个非常基础的概念.本文将对这两种常见的锁机制在数据库数据上的实现进行比较系统的介绍. 悲观锁(Pessimistic Lock) 悲观锁的 ...

  3. 再谈HTTP2性能提升之背后原理—HTTP2历史解剖

    即使千辛万苦,还是把网站升级到http2了,遇坑如<phpcms v9站http升级到https加http2遇到到坑>. 因为理论相比于 HTTP 1.x ,在同时兼容 HTTP/1.1 ...

  4. GALV_maptravel研究分析(2)

    本节地图:Gov's Mansion,Campsite,Yourmansion ++++++++++++++++++++华丽丽的分割线+++++++++++++++++++++++++++++++++ ...

  5. Python 较为完善的猜数字游戏

    import random def guess_bot(): bot = random.randint(1, 100) # time = int(input("你觉得能猜对需要的次数:&qu ...

  6. 2.2JAVA基础复习——JAVA语言的基础组成运算符和语句

    JAVA语言的基础组成有: 1.关键字:被赋予特殊含义的单词. 2.标识符:用来标识的符号. 3.注释:用来注释说明程序的文字. 4.常量和变量:内存存储区域的表示. 5.运算符:程序中用来运算的符号 ...

  7. MySQL5.7 并行复制的学习

    MySQL 5.6 基于库级别的并行复制 MySQL5.6的并行复制是库(schema)级别的,从库为每个库(schema)分配一个线程以此来提高复制效率 在MySQL 5.6版本之前,Slave服务 ...

  8. Bugku-CTF之never give up

    Day23 never give up http://123.206.87.240:8006/test/hello.php   本题要点:url编码,base64编码,代码审计,php函数       ...

  9. JavaScript中对象和数组的深拷贝

    不管是在面试中还是我们的项目中经常会用到数组或者对象的深拷贝,下面我就自己总结的分享给大家. 首先要知道什么是深拷贝?什么是浅拷贝? 深拷贝:源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另 ...

  10. topcoder srm 615 div1

    problem1 link 对于数字$x$,检验每个满足$x=y*2^{t}$的$y$能否变成$x$即可. problem2 link 如果起点到终点有一条长度为$L$的路径,那么就存在长度为$L+k ...