OO第二单元总结

一、设计策略与基于度量分析

1.1 第一次作业

设计策略分析

第一次作业是单部多线程可捎带电梯。

只有一部电梯并且在电梯中判断方向等就没有设置调度器,所以只需要输入线程和一个电梯线程进行多线程协同。

在主类中start了输入线程和一个电梯线程,传入同一个队列作为共享队列,输入线程负责添加向队列中添加乘客,电梯线程负责处理队列中的乘客。当时不太理解wait和notify所以并没有实质上使用到,而是使用了wait(time)方法让电梯线程自动醒,在只有两个线程的情况下这种方法确实也可行。

电梯调度策略采用LOOK算法,当前运动方向能接到的人员都可以上电梯,当前运动方向内外均无请求时电梯反向。

新建了一个Alive类并创建一个实例传入两个线程中,输入结束就set其中的成员变量,电梯类根据成员变量的值决定是否可以结束线程。

基于度量分析

UML类图

类复杂度

电梯类中需要处理上下,进出人等各种调度,所以复杂度较高。

方法复杂度

由于上下人合并在一个方法中,需要的处理比较多。

1.2 第二次作业

设计策略分析

第二次作业为多部多线程可捎带调度电梯。

 相对第一次作业改动不大,只在一些地方加入了人数的判断,每个电梯线程拥有一个队列,输入线程负责把乘客均摊给每个队列。

由于沿用了第一次作业的wait(time),在多线程协同方面出了问题。

基于度量分析

UML类图

类复杂度

方法复杂度

1.3 第三次作业

设计策略分析

这次作业加入了调度器master进行乘客分配和通过输入线程调用master初始化电梯线程。 

每种电梯一个等待队列,所有需要换乘的乘客在1或15层进行换乘,调用master的方法放回等待队列。

这次采用了wait和notifyAll进行多线程协同,有出现死锁问题。

基于度量分析

UML类图

类复杂度

依然是电梯类复杂度较大。

方法复杂度

 

 二、第三次作业可扩展性

SOLID原则

SRP(单一责任原则)

设计基本符合该原则。

也可以把电梯上下和开关门功能细分。

判断人员放入的队列也可以新开一个类。

OCP(开放封闭原则)

可以通过增加调度器的方法来实现新功能。但是如果改变一些基本属性修改是有必要的。

LSP(里氏替换原则)

本单元没有用到继承。

ISP(接口分离原则)

本单元没有用到接口

DIP(依赖注入或倒置原则)

模块间没有层次化的关系。

三、Bug分析

1.死循环,如果电梯此时内外均无人时有乘客到来且与电梯此时设定的运行方向不一样会进入死循环,注意在电梯空等的情况下两边的来人都测一下。

2.第二次作业沿用了第一次作业的设计,用了wait(time),这个在第一次作业两个线程还行,第二次强测环境下即使只开了三个电梯Input线程还是有可能抢不到CPU,而且还是在设了优先级增大了概率的情况下,炸了一半测试点,改成wait,notify就好了。建议可以第一次作业就开多个电梯。

3.第三次作业互测中遇到死锁bug

RTLE,进程没结束就不输出了,三个电梯内均未结束线程。

最后输出是C电梯关门,通过输出大法初步判断是C电梯判断循环条件master.empty()的时候卡住了。master是调度器,这个方法用来判断是否还有未完成的请求。由于是synchronized方法,需要master对象锁。

注意到前面的输出中B线程OPEN-OUT之后就没有输出了,而OUT的循环中有一个synchronized void master.putBack()方法,用来将换乘人员放回电梯等待队列(每种电梯一个队列),调用这个方法卡住的时候该换乘人员要放回A电梯的等待队列,也就是需要A队列的锁,但是A电梯此时并不占有队列锁。

采用jconsole工具查看死锁后发现,A队列的锁被输入线程占有。

当时输入刚好结束,输入结束的时候调用了一个非synchronized的master.notifyAllEle()方法来唤醒所有线程。写的时候是把三个synchronized(queue)嵌套了,Input线程此时在拥有A队列锁的情况下等B队列的锁。

情况是输入结束后Input线程先取得了A队列的锁在等B队列的锁,而此时B电梯线程在执行上下人操作拥有B队列的锁,在某位乘客换乘的时候B线程拿到了master的锁在等A队列的锁,A线程在等A队列的锁,C线程在等master的锁。

解决方案是把三个嵌套的synchronized(queue)拆开分别执行唤醒操作。putBack方法删去synchronized,本来这个方法加synchronized是考虑到判断empty,但是电梯类中实际是先putBack再remove的所以没什么问题,而且也可能和addNewPerson、addNewEle方法产生死锁。

四、互测策略

没有成功造出自动评测机。尽量交时间长一点的数据卡RTLE,或者交样例以及一些特殊边界数据。

五、心得体会

比起第一单元作业每次都重构,电梯单元作业基本都是在上一次的代码基础上改动。迭代开发确实省心省力。

可以在deadline前动笔,但是思考学习还是要尽早开始,第一次作业就应该掌握好wait和notify的用法而不是只想着过测试点。

这一单元学习到了不少知识,对面向对象方法的应用也更进一步了。

posted @ 2020-04-18 11:07  lidyo  阅读(164)  评论(0)    收藏  举报