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只需要加一句话就可以修正,但因为自身的拖延,没能在最后关头找到问题所在。
第三次作业的失败说明我对线程安全的理解还不够透彻,只知道在用到共享资源的地方都加上锁,不但影响效率,还容易造成死锁问题。
另一方面就是我对多线程程序调试效率的低下,无论如何都无法复现的情况下,也没能及时找助教反映,等到和助教确认问题的大致情况时,已经来不及重构。
本单元的作业中我对代码风格进行了一定的改进,深刻地体会到之前全然不顾代码风格的习惯的弊端,希望能继续保持。

浙公网安备 33010602011771号