一、总结分析三次作业中同步块的设置和锁的选择,并分析锁与同步快中处理语句之间的关系

作业1:

  同步块设置在dispatch类中,dispatch存放了输入线程和电梯线程之间的共享队列,其实质是电梯线程的外部请求队列。锁即dispatch类对象。同步块中处理语句,主要聚焦于外部请求队列的读和写,上锁就是读写互斥、写写互斥。

作业2:

  新增了输出线程的安全锁和同步块,防止输出not in order。

  其余的与作业1类似。

作业3:

  新增了Manager类的同步块和锁。manager是管理某座or某层的电梯的,里面有该处的电梯队列。之所以要对此电梯队列进行读写互斥加锁,是因为现在不止输入线程会调用manager,电梯线程在处理完请求的一阶段后也会调用manager中的电梯队列,从而可能导致线程安全问题。

 

二、总结分析三次作业中的调度器设计,并分析调度器如何与程序中的线程进行交互

  三次作业主调度器都为scheduler,作业2、3新增manager用于分配分配到该座or该层的电梯请求到具体的电梯中。

  作业1中,直接利用input线程调用scheduler将请求分配给相应电梯的dispatch(即外部请求队列)。

  作业2中,同上所述。

  作业3中, 在scheduler中对请求进行分析,变为1-3步的请求PersonAsk,再同上进行处理。

 

三、分析和总结自己三次作业架构设计的逐步变化和未来扩展能力

 作业1采用生产者消费者模型,UML类图如下,input线程调用调度器scheduler通过仓库dispatch跟elevator进行交互。

 

 作业2采用生产者消费者模型,UML类图如下,input线程调用调度器scheduler和manger类通过仓库dispatch跟elevator进行交互。使用manager类管理某座or某层的电梯队列。使用电梯工厂新增竖向和横向电梯。

 

 

作业3采用流水线架构。UML如图,新增PersonAsk来封装流水线请求,新增RequestCounter来检验流水线请求完成情况,input线程和电梯线程仍然使用scheduler处理请求。

 

 

三次作业的时序图为:

作业1:

 

作业2:

作业3:

 

四、分析自己程序的bug

分析未通过的公测用例和被互测发现的bug:问题特征和修复办法

第一次作业:

  公测pass。互测则是输出线程的不安全,即没有进行输出安全类的封装。

第二次作业:

  公测互测都是一个bug,即在横向电梯运行的时候,我采用的look策略当判断前方总是有人要上电梯时,会停不下来。这是电梯具体运行策略的bug。

  修复办法:对电梯空载走3步进行判断,如果是,说明本该3步以内上电梯的人没有上,即不该走了,该反向运行。

第三次作业:

  公测互测都是一个bug,来自于第二次作业的bug修复,即当反向时,没有在反向的那一楼座停留,判断是否有乘客要进入,而是直接反向走一步,所以该上车的永远没上车,RTLE。这还是电梯具体运行策略的bug。

  修复办法,将阈值改为4步即可。

 

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

列出自己所采取的测试策略及有效性

  我采用的是单元测试策略。即针对竖向请求、横向请求、换乘请求各自进行测试。如果单元测试都通过了,那么通过控制台的输出来判断是否存在线程交互的安全问题。如果没有,即代表代码无误。

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

  通过控制台输出的方式,即在每个线程的run结尾处打印线程结束语句,判断该线程是否即时结束,如若不然,则可以判断其出现死锁等线程安全问题。
分析本单元的测试策略与第一单元测试策略的差异之处

  第一单元是根据题目要求进行完备性的样例覆盖测试,对于输入输出有着较为明确和系统的规范,可以进行泛用。

  此单元题目要求比较简单,逻辑并不复杂,线程间的交互也比较明确,但解决的策略多样,不同调度算法可能有不同的bug,可以用完备的单元测试样例来检测bug,也可以看实际的代码来研究,从而进行针对性的bug测试。


六、 心得体会

  线程安全:

    一定要注意wait之后是否能够被唤醒。

    sychronized块尽可能写小。

  层次化设计:

    以类为思考对象,让类纯粹,用类与类的交互来解决问题。第1第2次的作业可以说是一脉相承,都是简单的生产着消费者模式,但是到了第三次架构,就需要使用流水线架构,不过本质上由于电梯就做电梯该做的事,不参与调度,所以我们主要需要在Scheduler类里面对请求进行流水线处理即可。

    学会运用工厂模式和单例模式。

    提取子类的共性到父类中去,将子类的特有的行为进行方法重写。