OO-2021-第二单元总结

注:本人三次作业中均没有实现调度器,对线程的同步设计最终也以失败告终。故仍按上一次博客模板书写。

一、程序结构与OO度量

第一次作业

(1)设计思路

设计模式

采用生产者-消费者模式。

 

 

 

创建一个输入线程,用来读取并产生新的乘客请求,放入等待队列并通知电梯。

创建电梯线程,负责在接到请求通知后,按照到达模式对应的策略运行。

创建一个请求队列作为两个线程共享资源。

 

不同到达模式下的运行策略:

总体:1.先计算接下来的目的楼层,如果电梯内有乘客,那么目标为第一个到达的乘客的目的楼层;否则去接收请求队列的头部乘客。

  2.向目的楼层运行,途中每层检查是否需要开门,判断标准是   有乘客需要进出电梯<=>内部乘客到达/外部乘客可捎带且容量未满。

  3.如果需要开门,则开门并进出乘客,关门,回到第1步。

Random: 没有特别的运行策略。

Night: 每次取队列中最高楼层的请求为目的楼层,以减少往返,最大程度捎带。

 

 

 

 

 

Morning:根据到达特点,检查等待队列,每次有乘客到达后,再多等待2s。当2s后无新乘客/队列乘客数已经达到容量上限时,再出发。

捎带策略:采用ALS策略

先确定主请求,运送主请求的途中,接收方向一致的乘客。

 

 

 (此处有严重的策略漏洞,导致最后没能通过中测。)

 

(2)类图

除了用于测试的主函数类Test,有四个其他类:

Input: 输入线程,读取输入后,将请求放入请求队列。

Elevator:电梯线程,从请求队列获取请求,负责在有请求出现时,按照到达模式运行。

WaitQueue: 请求队列,是线程间的共享资源。

Passenger: 乘客类,属性有id, 出发楼层和到达楼层。

具体的属性、方法和类图如下:

 

(3)OO度量

类:

 

 

 

 方法:

 

第二次作业

(1)设计思路

电梯总体保持第一次的设计,但修正了第一次作业中的一个开门判断的bug。

通信机制:

使用了wait-notify的方式,当请求队列中没有乘客时,电梯线程调用wait()方法进入等待,当新请求到达或者输入结束时,输入线程调用notifyAll()方法,唤醒电梯。

 

 

同步机制:

线程间的共享资源为等待队列,通过使用synchronized()将涉及到读写等待队列的语句放入临界区来进行同步。

 

 

(2)类图

 

 

 

 

 

(3)OO度量

类:

 

 

 

 

 方法:

 

 

 

 

 

 

第三次作业

总体设计与前两次作业相似。

主要改动:

1.根据不同型号电梯的功能区别,修改了电梯构建方法。

2.根据可到达楼层更改了电梯的停靠策略

 

遇到了疑似线程冲突的问题,但是一直没能复现出来,也没来得及重构,最终没能通过中测进阶样例。

 

二、自己程序的BUG

第一次作业的开关门判定策略中,在判定“请求的目标方向与电梯运行方向是否一致”时出现了问题,忽略了电梯内没有人且接下来目标恰好在本层时的情况。

修改方式:增加了一种开门情况,即当电梯内为空时,无论对应楼层的请求方向如何,均要开门。

 

 

第三次作业在评测机评测时出现了Runtime Error, 但不知道具体的异常信息。据推测是线程冲突问题。然而线下对出现问题的样例进行测试时,即使利用定时投放模拟完全相同的情况也无法复现。因为对线程调度的理解不够,相关的设计有诸多问题,只能通过重构来解决,但时间上已经来不及,遂作罢。

三、心得体会

第一次作业因为一个小的BUG成了无效作业,而这个BUG只需要加一句话就可以修正,但因为自身的拖延,没能在最后关头找到问题所在。

第三次作业的失败说明我对线程安全的理解还不够透彻,只知道在用到共享资源的地方都加上锁,不但影响效率,还容易造成死锁问题。

另一方面就是我对多线程程序调试效率的低下,无论如何都无法复现的情况下,也没能及时找助教反映,等到和助教确认问题的大致情况时,已经来不及重构。

本单元的作业中我对代码风格进行了一定的改进,深刻地体会到之前全然不顾代码风格的习惯的弊端,希望能继续保持。

 

posted @ 2021-04-27 14:43  1506zzn  阅读(57)  评论(0)    收藏  举报