OO第二单元总结

第二单元总结

一、同步块和锁

本单元作业中,我全部采用了synchronized、wait()、notifyall()等操作来实现同步块和锁,并未采用lock等操作。主要原因是本单元第一次作业时,我只了解前者,而后两次作业中,我都只是对第一次作业的代码进行了部分修改、增量开发,并没有对原始架构、进程同步实现机制进行改动。

我个人加锁的原则很简单:只加不得不加的锁,锁应尽可能地少。这主要是我在本单元起步阶段通过与其他同学交流、浏览网络资源得知,加不必要的锁,不仅会对性能产生影响,还容易产生死锁、不应该的唤醒等较为隐蔽的bug。

这三次作业中,我都主要在两处加了锁:

1、input类和schedule类。在我的架构中,input类为生产者,schedule类为消费者,中间存在了两个共用对象elevatorQueue、personQueue,因此在这两个类中对这两个共用对象不得不加锁,以保证线程安全。

2、各方法若涉及到对队列进行遍历操作且有增减操作,必须加锁。

对第二点,我还有话要说。在单线程时,若在遍历途中删减元素,线程有时会报错“Exception in thread "xxxx" java.lang.NullPointerException”,解决方法也很简单、多样,我采用的是将列表先进行Iterator操作,就可避免此类报错。但是,在多线程时,尽管使用Iterator操作进行了处理,有时还是会报错,这便是线程不安全所导致的,需要加锁。

二、调度器设计

本单元的三次作业,我的调度器设计没有发生变化。

我将调度器作为了一个类,即schedule类,也是本模型中的消费者。该调度器实现的功能很简单:

1、获取input类(生产者)生产的新人、新电梯。(从托盘elevatorQueue、personQueue中获取)

2、根据上一步获取的人的起始点,将这个人加入到他将会乘坐的电梯的等待队列中。在本过程中,会对是否要换乘进行判断,若需要换乘,以需要乘坐三部电梯为例,调度器会在分配前就确定好这个人会乘坐哪三部电梯,然后直接将这个人加入到这三部电梯的等待队列之中。对于换乘的其他细节,会在下文详细介绍。

三、具体电梯实现

首先,我需要声明,本三次作业的架构一致,仅仅在方法实现上进行了增量开发,故在此只以第三次作业为例对电梯实现进行分析。

1、类图

第三次作业的类图如下:

2、协作图

第三次作业的协作图如下:

在此对电梯线程终止条件做一下具体描述:电梯的等待队列没人,电梯内没人,调度已完成(该条件的前提是输入已完成)。

3、架构设计

我选择的是生产者-消费者模型,input类为生产者,schedule类为消费者模型,托盘为两个队列:人队列与电梯队列。

我的主调度器只负责将人队列中的人逐个分配到这个人将要乘坐的电梯的等待者队列中,之后的调度则由电梯内部的调度程序完成。

我的电梯实现过程与大部分同学相比有以下几点不同:

1、对于换乘,我的解决方法是:以需要乘坐三部电梯的人为例,在主调度器中,我就把这个人要乘坐的三部电梯确定好,然后将这个人一次性加入到这三部电梯的等待者队列中。在这里,有读者会产生疑问了,如何保证先后顺序?我的想法是,如果在人的属性中加入这个人当前的楼座楼层、中转电梯的楼层,再与最终目的地相比较,我们就可以得出他将要乘坐哪一部电梯;我还在人的属性中加入了IsIn,用于标记这个人是否正在电梯中,以便于中途的一些判断。

我认为我的换乘解决方法虽然有些呆板,最开始就决定乘客的所有电梯选择,对效率会有一定影响,但是,它简单暴力易实现啊~

2、对于电梯的run方法,我选择的实现是,每一次循环,电梯只移动一层或不动。具体流程如图:

过程非常有序,这也给编程带来了方便。

四、自身bug分析

综合三次作业来看,我出现的bug主要有以下几种:

1、第一次作业的策略部分,因为纠结于look和tls,所以最终策略有点四不像,导致部分强测点运行时间过长。

2、第三次作业中,选择最佳换乘策略过程中,有一步是获取总距离最小值,我对此设置了变量min,在之后的遍历过程不断修改min值,最终得到最小值。但是我在设置min初值时考虑不周,初值设置过小,导致部分测试点出bug。

3、在这三次作业的中测阶段,我都遇到了cpu运行超时的问题,最终解决时发现都是在电梯运行过程中发生了轮询,也就是空转。经过了三周的磨练,我已经能够较熟练地使用”print“大法来锁定、解决轮询问题。至于”print“法是什么,大家可以参考讨论区。

五、互测策略

在3次互测中,我都选择了偏摆烂的做法:数据轰炸。即在限定的时间的前0.1秒,一次性输入大量指令,有时是同起点,有时是同终点,有时无规则等等。不过不幸的是,我只在第一次作业的互测阶段hack到了人,之后两次都没有成功。

六、心得体会

这一单元中,我最大的体会仍然是:一个好的架构设计非常重要!!!

在这三次作业中,我基本是沿用了第一次作业的架构,之后的两次作业仅仅是对其进行局部修改、增量开发,且主要集中在elevator类。

不过,我的缺憾也是极其明显的:我对横向电梯的处理完全沿用了纵向电梯。我将原本是由ABCDE连成的环,简化为ABCDE组成的线,也就是说我的A和E是不连通的。”好处“很显然,我只需要对纵向电梯做出一丁点修改就完全可以胜任我这个低配横向电梯(还是太懒了……);坏处更明显,AE不连通导致性能肯定不如环形横向电梯。

因此,在日后的JAVA编程中,我会投入相当一部分精力用于设计一个可拓展性强的好架构;同时,我要克服自己的懒惰!

posted on 2022-05-03 23:07  哇哈哈小太阳  阅读(35)  评论(0编辑  收藏  举报