oo第二次总结作业

OO电梯作业总结

  这三周的作业和课堂内容以及OS的课上内容都相同,都是关于多线程方面的知识。在这次作业中由浅入深布置了三项多线程电梯方面的作业,让我们在实践中感受了多线程的工作原理以及各项需要注意的要素。

一、第一次作业

  第一次作业是典型的生产者消费者问题,只不过生产者不必考虑容器装满的特殊情况。在这次电梯作业中电梯只需要将乘客送往目标楼层,不需要解决沿路搭顺风车等其他需要解决的特殊情况。当负责输入的生产者停止时,设置一个共享的结束变量结束整个电梯的运行,整个电梯的运行结构如下图所示:

  如图所示,整个电梯总共包含2个线程,即电梯线程和输入线程,两者通过结束信号进行通信。同时两者共享一个共享变量:等待队列。在多线程环境下势必会出现两者共同访问导致数据冒险的情况。我采取的解决方法是将等待队列类中的每个函数设定为静态函数,并加上synchronized修饰。通过百度和自身的实践,这样操作的实际效果是对类本身进行加锁,即当一个静态函数被调用时禁止其他静态函数被调用。这样操作的确可行,但是由于是在函数上加锁,性能方面不如对特定变量,但好处是能够有效地确保正确性。

  本次作业的类图如下所示:

代码分析如下:

  可以看见在电梯类中我的写法没有做到完全对任务进行细分,而是一个run方法走到底,因此代码的复杂性较高。在接下来的任务中我注意到了自己的问题,对任务进行更细的划分。

BUG分析

  这一次作业由于比较简单,在互测以及强测中都没有发现任何BUG。

第一次电梯作业总结

 第一次作业是对多线程的试水,在其中我初步感受到了多线程的设计风格,同时大致确立了电梯问题的整个架构。在接下来的作业中都是沿用输入队列,等待队列以及电梯3类的架构进行设计。

二、第二次作业

         这一次的电梯作业相比上一次的电梯作业增加了2个难点。第一,这一次的电梯是ALS电梯,需要额外考虑2个环节。首先电梯在上升时需要考虑对同方向乘客的捎带,同时由于电梯内部可能有多于一个乘客的情况,因此需要额外增加一个队列记录电梯内部的人员请求。第二,这一次作业增加了对于CPU运行情况的检查,因此无法在这一次作业中使用轮询算法,必须运用锁控制查询,降低CPU使用率。

   受到OS课程的影响,相比较synchronized,notify(),我偏向更加简单直接的Semaphore,因此在这次作业中我主要使用Semaphore实现进程同步和互斥。

   首先列出这次作业的主要流程架构:

   捎带的解决方法如图中所示。首先创造运行队列,将电梯中的所有人的请求加入运行队列。其次在每一层都检查等待队列中是否有满足捎带条件,如果有则加入运行队列中。最后再谈谈我是怎么解决轮询问题的,我所采用的方法是最简单的方法,即在每次搜索结束之后进行sleep操作,减少CPU使用。当然合理利用信号量肯定是最高效的解决方案,因此在第三次作业中我采取了另一种方案。

  以下是本次作业的类图以及代码分析:

  由于这次电梯作业中啊需要使用到大量的if判断,包括电梯的运行方向,查找操作以及判断当前层数是否为0等,因此这次的代码复杂度普遍较高。可以改进的做法是对函数功能进行进一步的细分。在这一次作业中为了更高的准确性和代码的直观性,我没有进一步细分,导致代码复杂度较高。

BUG分析

   在中测中主要出现了一个BUG,就是CPU超时,通过sleep()便可顺利解决。然而强测只得了26分,原因特别简单,也特别愚蠢。在电梯向下运行进行顺带判断时,不慎将>写成了<,直接导致测试点全挂。也算是一个教训。代码上任何一点微小的错误将导致整个崩盘,因此必须在每次中测时做好课下测试,写自己的评测机,最大限度地杜绝这种情况再次出现。

三、第三次作业

 第三次作业本质上相较于第二次作业增加了2个方面。第一是电梯变多了,因此需要创造更多的运行队列,同时对等待队列需要进行访问加锁控制。第二点也是这次作业的难点,由于部分请求无法由一个电梯完成,因此需要采取合理可行的措施实现多电梯协作。对于该问题的解决我通过改写PersonRequest类实现,在其中添加了label,realend,available三个变量进行实现,对这种特殊情况的处理在等待队列中实现,具体方法如下图所示:

  对于我的处理架构,在这次作业其实还有一个隐藏的难点,那就是一台电梯关闭时机的判断。当输入线程关闭时且等待队列为空时不能够关闭电梯,因为label=1的运行队列中的请求会重新加入等待队列。解决方法有2个,第一是让每个电梯线程能够访问其他电梯的运行队列,当输入线程关闭,所有的运行队列都为空并且等待队列为空时,同时结束所有电梯线程。我认为电梯运行队列应该由本电梯完全掌握,因此采取第二种做法,在输入线程结束并且等待队列为空的情况下,当等待每部电梯都处于查询等待队列状态并且第一次查询未找到时,将每部电梯的一个特征变量设置为1,当所有特征变量设置为1时,同时关闭所有电梯。

  总体上这一次作业的队列类以及电梯很好地复用了上一次的作业,对电梯的修改是增加了对label=1任务的特殊处理,对满员情况的判断以及在线程结束时的特殊处理。对队列的修改包括增加了2个运行队列,以及在将输入线程的请求读入等待队列时判断可执行的电梯,写入available,同时对不可执行的电梯作label=1的特殊处理,第三次作业的类图以及代码分析如下图所示:

  这一次的代码风格明显有很大的不足之处,原因之一是这一次的作业大幅度复用了上一次作业的样板,因此在电梯类中代码的复杂度较高。第二个不足之处是没有在电梯类中实现继承或者创建一个泛化的电梯类。这次作业中三个电梯明显有很大的相同点,只是在个别属性上不同。将代码进一步细化并且熟练实现以及掌握继承是需要在接下来的学习中注意的地方。

BUG分析

  这一次的作业比上一次更加悲剧,中测未能通过。最终发现原因也特别简单,在电梯顺带时完全沿用了上一次的模板,忘记进行修改,导致电梯在等待队列提取请求时根本就没有判断当前楼层是否能停靠,直接导致整个测试崩盘。这也给我带来了第二个教训,那就是不能太急着写代码,而是应该先详尽地对整个任务进行细节分析,列出所有需要扩展的地方再进行修改,否则就会像这样在细节处崩盘。

四、互测BUG分析策略

  首先这一次的电梯作业测试难度明显上升,无法运用简单的控制台输入输出得到正确结果,因此在正式进行测试之前我通过讨论区的指示自己写了一个评测机,在另一个文件中间段输出自己设定的指令,同时替换输入线程的方法,通过process类读取文件中的指令实现按照特定时间输入的效果。

  第一次作业互测:这一次作业的互测其实并没有太多BUG可以发现。我注重两方面的BUG,一是对电梯关闭时机的测试,第二则是电梯是否能够正确运行。结果并没有在互测中发现BUG。

  第二次作业互测:这一次作业我受到了多次攻击,主要来自于强测的错误,将>误写成<.这一次的强测我注重两个方面的测试,首先是在边缘时间投放测试点,即电梯关门的瞬间投放请求,如果在开门时搜索等待队列则会错过该请求。第二是对电梯运行通过0层的测试,在互测中共DE出2个BUG。

  第三次作业互测:由于没有通过中测,因此很不幸没有进入第三次互测。

五、心得与体会

  多线程处理无疑是每个程序猿的基础技能,这次的作业只是为我们开了一个非常初步的头,接下来还有无穷无尽的知识点需要我们自己去探索。在这次作业中虽然成绩不够理想,但是静下心来还是获得了不少的经验和教训,包括对编程方法的反思,对细节的把握,以及代码风格架构的进一步优化,这都是我需要在接下来的作业中不断改进的地方。在接下来我需要更进一步,积极了解阅读关于JAVA方面的常识和知识,使得自己具有更加强大的专业技能,同时让自己不至于在细节处再次翻车。

原文地址:https://www.cnblogs.com/h87d/p/10760033.html