2019-北航面向对象-电梯作业总结

时间:2023-01-24 17:21:19

第二单元(电梯)总结性博客作业

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

   第一次电梯作业(多线程、单电梯、非捎带):在第一次作业中我一共设置了五个类:Test类包含主函数,负责实例化进程,并将共享类作为参数传入两个线程;Poly类存储请求,每个请求对应一个PolyRequest类即为输入请求类,将请求不断读入共享队列;Share及共享类,其中包含了请求总队列;Elevator及电梯队列,不断从共享队列中读出请求,并执行。在这次作业中,我采用傻瓜调度的方式,及不考虑时间性能方面,Request每次只能向共享队列中输入一条请求,Elevator只能从共享类读出一条请求,采取先入先出的原则,及先发出的请求先被执行。于此同时,RequestElevator并行,协同进行。

第二次电梯作业(多线程、单电梯、捎带):在第二次作业中我一共设置了五个类:Test类包含主函数,负责实例化进程,并将共享类作为参数传入两个线程;Poly类存储请求,每个请求对应一个PolyRequest类即为输入请求类,将请求不断输入共享队列;Dispatch及共享类,其中包含了请求总队列,以及一个电梯一轮捎带所执行的请求队列,还包括了电梯一轮捎带的一些基本信息。除此之外,这个类还是调度器,调度器负责判断捎带的条件,将可以被捎带的请求放入捎带请求队列;Elevator及电梯队列,执行可稍带队列中的指令,在经过每一层时判断在这一层有无进出操作,并对队列进行更新。在这次作业中,我讨论了6种捎带模式,其他与第一次相同。于此同时,RequestElevator并行,协同进行。

第三次电梯作业(多线程、多电梯、捎带):在第三次作业中我一共设置了五个类:Test类包含主函数,负责实例化进程,并将共享类作为参数传入InputRequest线程和三个Elevator线程;Poly类存储请求,每个请求对应一个PolyInputRequest类即为输入请求类,将请求不断输入共享区,及DispatchDispatch及共享类,其中包含了ABC三个电梯的三个请求总队列,并起到调度器的作用,及判断从InputRequest中输入的请求应该放入哪一个电梯的队列,如果遇到不能直达的情况,则将指令进行拆分,两个分指令分别放入不同的电梯队列。;Elevator及电梯队列,包含一个电梯一轮捎带所执行的请求队列,还包括了电梯一轮捎带的一些基本信息。除此之外,这个类还包括判断捎带的条件,将可以被捎带的请求放入捎带请求队列,电梯执行可稍带队列中的指令,在经过每一层时判断在这一层有无进出操作,并对队列进行更新。在这次作业中,我讨论了6种捎带模式,其他与第二次相同。于此同时,Request和三个Elevator并行,协同进行。

2019-北航面向对象-电梯作业总结

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

(1)度量类的属性个数、方法个数、给个方法规模、每个方法的控制分支数目、类总代码规模

  第一次电梯作业(多线程、单电梯、非捎带):

2019-北航面向对象-电梯作业总结

 

第二次电梯作业(多线程、单电梯、捎带):

2019-北航面向对象-电梯作业总结

第三次电梯作业(多线程、多电梯、捎带):

2019-北航面向对象-电梯作业总结

(2)计算经典的OO度量

  第一次电梯作业(多线程、单电梯、非捎带):

2019-北航面向对象-电梯作业总结

第二次电梯作业(多线程、单电梯、捎带):

2019-北航面向对象-电梯作业总结

2019-北航面向对象-电梯作业总结

2019-北航面向对象-电梯作业总结

第三次电梯作业(多线程、多电梯、捎带):

2019-北航面向对象-电梯作业总结

2019-北航面向对象-电梯作业总结

(3)画出自己作业的类图,并自我点评优点和缺点,要结合类图做分析

  第一次电梯作业(多线程、单电梯、非捎带):

  优点:类的关系比较清晰,线程安全

  缺点:采用傻瓜调度,性能过低

2019-北航面向对象-电梯作业总结

第二次电梯作业(多线程、单电梯、捎带):

  优点:线程安全,且捎带讨论的比较清晰,复用性较强

  缺点:性能分数不高,说明性能还可以优化,且结构还可以更加清晰些,有些方法用的不是很好。

 2019-北航面向对象-电梯作业总结

第三次电梯作业(多线程、多电梯、捎带):

优点:线程安全,结构比较清晰

  缺点:性能分数太低,几乎没得到性能分,说明性能还可以进一步优化

2019-北航面向对象-电梯作业总结

(4)通过UML的协作图(sequence diagram)来展示线程之间的协作关系

第一次电梯作业(多线程、单电梯、非捎带):

2019-北航面向对象-电梯作业总结

第二次电梯作业(多线程、单电梯、捎带):

2019-北航面向对象-电梯作业总结

第三次电梯作业(多线程、多电梯、捎带):

2019-北航面向对象-电梯作业总结

 

(5)从设计原则检查度量,检查自己的设计,并按照SOLID列出所存在的问题

2019-北航面向对象-电梯作业总结

三、分析自己程序的bug

(1)分析自己未通过的公测用例和被互测发现的bug;特征、问题所在的类和方法

第一次电梯作业(多线程、单电梯、非捎带):通过了全部的公测用例,未在互测中被发现bug

  第二次电梯作业(多线程、单电梯、捎带):通过了全部的公测用例,未在互测中被发现bug

第三次电梯作业(多线程、多电梯、捎带):通过了全部的公测用例,未在互测中被发现bug

(2)特别注意分析哪些问题与线程安全相关

在自测的过程中出现过线程错乱的问题,因为没有锁起而造成的。

(3)关联分析bug位置与设计结构之间的相关性

  在提交的过程中有过CPU超时的现象,说明程序中存在轮询的情况,及CPU一直处于等待状态,解决的办法是在continue前面加上一个sleep或者使用waitnotify

四、分析自己发现别人程序bug所采用的策略

(1)列出自己所采取的测试策略及有效性,并特别指出是否结合被测程序的代码设计结构来设计测试用例

(2)分析自己采用了什么策略来发现线程安全相关的问题

(3)分析本单元的测试策略与第一单元测试策略的差异之处

第一次电梯作业(多线程、单电梯、非捎带):第一次作业我主要测试了连续输入和程序停止部分,因为此次作业仅有一台,且基本上都是傻瓜调度因此没有查到错误

第二次电梯作业(多线程、单电梯、捎带):第二次作业使用了第一次电梯作业中的强测数据对别人程序进行了测试除此之外,在写程序时,我积攒了一些测试样例,在互测时起到了作用。第二次作业相比第一次增加了捎带功能,因此,我主要针对各种捎带的情况进行了测试。我在看他人代码的时候弄清楚他的捎带策略,根据其结构设计一些设计样例来测试其性能。我发现大家的程序运行结果还是有很大的差别,同一组数据有的程序30s之内就能运行完,有的却要70s左右,但是测试结果表明,它们都在合理时间范围内,只是性能上有所差距。

第三次电梯作业(多线程、多电梯、捎带):第三次作业,我先在互测时用第二次电梯作强测的数据进行了一下测试除此之外,在写程序时,我积攒了一些测试样例,在互测时起到了作用。相比前两次作业,第三次作业增加了两个电梯,同时存在不直达需要转乘的情况,因此将全部需要转乘的情况全部列了出来,依次进行测试,判断其是否存在转乘错误的情况我在写测试数据时会先看明白它们的捎带规则和转乘规则,然后根据不同的架构和设计方式编写测试用例。结果发现,大家的转乘方式以及捎带规则还是有很大的差别,性能上也有一定的差距。测试数据如:1-FROM--3-TO-22-FROM-10-TO-19

五、心得体会

(1)从线程安全和设计原则两个方面来梳理自己在本单元三次作业中获得的心得体会

  线程安全和设计原则是我在做这一单元作业时思考做多的问题。好的设计架构是保证线程安全和可复用性的保证。线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他操作,调用这个对象的行为都可以获得正确的结果,那么这个对象就是线程安全的。类要成为线程安全的,首先必须在单线程环境中有正确的行为。如果一个类实现正确,那么没有一种对这个类的对象的操作序列可以让对象处于无效状态,观察到对象处于无效状态、或者违反类的任何不可变量、前置条件或者后置条件的情况。此外,一个类要成为线程安全的,在被多个线程访问时,不管运行时环境执行这些线程有什么样的时序安排或者交错,它必须仍然有如上所述的正确行为,并且在调用的代码中没有任何额外的同步。其效果就是,在所有线程看来,对于线程安全对象的操作是以固定的、全局一致的顺序发生的。

我在这三次作业中都设了一个input线程,及不断地向队列中输入数据,一个elevator线程(第三次作业对应三个elevator线程),及从共享队列中读出数据后指导电梯运行,还有一个共享类,这个共享类中存储了总队列,并起到调度器的作用。从线程安全的角度考虑,当共享类中的数据被读取或存入时,同时只能有一个进程对这个数据进行操作且进行操作的代码的执行不能被打断,这样就保证了程序在运行的过程中不会因为进程混杂交错而造成数据错误或者运行错误。为了保证线程安全,我将方法锁了起来,及使用synchronized 关键字,代表这个方法加锁相当于不管哪一个线程例如线程A),运行到这个方法时,都要检查有没有其它线程B或者CD正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B或者C D运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。