OO第二单元总结
前言
又经过了三周艰难的面向对象课程的学习,又到了我们最喜欢的写博客总结环节。说实话,经过了三周的锤炼,对于多线程相关的知识,我还是学到了不少的。
第一次作业
程序分析:
电梯作业,我逐渐走上了一条面向对象的路,一共使用了7个类。分别是主类,调度器类,人线程类,人本身类,电梯线程类,电梯本身类,结束判断类。
复杂度分析:
时序图:
设计思路:首先使用一个主类来初始化两个线程:电梯线程和人的线程类,然后开始运行线程。人的线程类负责处理从标准输入之中读入的数据,并在结束输入之后退出该线程。人本身类是一个抽象出来的代表每一个请求的对象类,用来向调度器添加需求指令。电梯线程类负责取指令并执行一条指令,同时判断是否运行结束。电梯本身类用来实际上模拟电梯的运行,包括用接收到的指令并且输出正确的结果。结束类用来判断是否已经结束并且把信息传给电梯类。
优缺点:这次作业的代码量比较小。我认为我设计的优点是使用了一个结束类来判断是否结束。当结束输入时,将结束类的一个标志变量设置为true,电梯类通过判断请求指令是否还有剩余以及标志变量是否为true来判断指令是否结束。关于这次设计的缺点,我觉得是我自己想的是把人的指令本身和电梯本身进行抽象出来单独做成一个类,但是这样其实让结构看上去有一些冗杂。
发现bug:第一次电梯作业由于采用了傻瓜调度方式,调度方式非常清楚明了简单,无论是强测还是互测都没有发现这次作业的bug。
结论:第一次的电梯由于难度门槛相对较低,代码量也不是太多,所以我的完成还是相对轻松一些的。但是多线程还是让我学到了不少。我采用了synchronized代码块来作为同步锁。这次的电梯作业只是一个基础的版本,但是他给我之后两次相对更加复杂的电梯的设计提供了一些架构和设计的思路。
第二次作业
程序分析:
第二次作业我依然采用了7个类来实现电梯的功能。分别是主类、调度器类、人线程类、人本身类、电梯线程类、电梯本身类,和判断结束的类。
复杂度分析:
时序图:
设计思路:与第一次电梯作业类似。首先使用一个主类来初始化两个线程:电梯线程和人的线程类,然后开始运行线程。人的线程类负责处理从标准输入之中读入的数据,并在结束输入之后退出该线程。人本身类是一个抽象出来的代表每一个请求的对象类,用来向调度器添加需求指令。电梯线程类是一个中间的类,用来表示电梯线程。电梯本身类是一个抽象出来的用来模拟电梯的类,接受指令,每一层与控制器进行交互,判断在该层有没有捎带请求,同时执行ALS可捎带电梯的执行。结束类仍然是用来判断是否已经结束并且把信息传给电梯类。
优缺点:这次作业的代码量比起上一次增加了不少。我认为自己此次设计的优点是把电梯的局部运行策略放在了电梯类里面进行执行,这样为第三次作业提供了一些方便。同时,我在设计电梯的开门动作和关门动作的时候,在开门输出前,先判断有没有要搭载的乘客,而在输出关门前也同样再判断是否有可疑以捎带的乘客。同时,我也用了一个专门的下电梯的方法来处理乘客下电梯的需求,而开门关门方法则专门用来处理捎带的请求或者初次请求。对于本次设计的缺点,我认为是没有很好的做好可扩展性。所有的信息都被用固定的变量写死在调度器类和电梯类了,导致我自己第三次作业面临着部分的重构。
发现bug:第二次电梯的模式,我是基本完全按照指导书的思路进行设计。在开始自己的自测和评测机的强测都没有发现我有什么bug。后来在第三次作业的一个测试中,我发现了第二次作业存在着一个不会被判为错误的“bug”。我自己的设计过程在处理第一条指令的时候有可能会在到达了指定的楼层之后,先进行一次开门和关门的操作,中间没有人进入。紧接着,电梯会再次进行开门和关门操作,同时指令中的人会进入电梯。究其原因是我自己在设计的时候采用了while循环,先判断是否有人下电梯,但是开始时候并没有人下电梯,虽然不会凭空造人或者吃人,但确实是一个小问题。
结论:第二次设计的ALS可稍带电梯主要是在电梯的如何执行的部分进行了更改,通过电梯在每一个楼层同调度器的交互来实现对捎带请求的实现。依旧采用了synchronized对象锁来对人线程和电梯线程的共有调度器的访问和修改,最后基本完成了要求。
第三次作业
程序分析:
这次作业我使用了7个类。分别是主类,调度器类,人线程类,人本身类,电梯线程类,结束类,和一个替代类。部分精简了一些地方,避免了冗杂。
复杂度分析:
时序图:
设计思路:这次作业依旧采用了前两次作业的整体上大致相同的结构。首先使用一个主类来初始化两个线程:电梯线程和人的线程类,然后开始运行线程。人的线程类负责处理从标准输入之中读入的数据,并在结束输入之后退出该线程。人本身类是一个抽象出来的代表每一个请求的对象类,用来向调度器添加需求指令。调度器类这次有较大的改变。调度器有一个主队列,用来负责存储从输入中读入的请求数据。同时构造三个小的队列分别用来向三个电梯线程提供需要的请求。在调度器内,主队列每收到一条请求,先判断是否需要换乘,然后把它分配给小的队列。电梯类综合了只前两次作业的电梯线程类和电梯本身类,用一个类来模拟一个电梯的运行。仍然采用第二次作业的ALS可捎带电梯的执行策略方法,每一层斗都与调度器进行交互,判断是否可以捎带。结束类仍然是用来判断是否已经结束并且把信息传递给每一个电梯线程。替代类是当时还没有新的PersonRequest接口的时候,我想到的一个存储三元组的替代类,用来代替PersonRequest和电梯进行数据的交互。
优缺点:关于这次电梯设计的优点,我记得老师在上课的时候也提到了,使用三个小的队列来分别和三个不同的电梯线程进行交互,电梯只和小队列进行数据的交换,变的有效率,同时降低了出现问题的几率。对于这次作业的设计缺点,我认为是这样的,我的替代类的设计感觉有些不那么面向对象。之前我发现PersonRequest并不能自己创建,因而我新建了一个替代类,用来表示一条指令的ID,FromFloor,ToFloor三元组,然后传入电梯的数据也是三元组。感觉这个设计就很无奈。后来接口开放了可以自己创建,但是我并没有更改。
发现bug:各种测试过程中,没有发现有什么问题,当然,上一次那个灵异的先开门关门事件当时没有解决。是后来自己发现已经通过弱测之后发现的。但是,我在开始的时候曾经遇到过CPU时间太长的问题,后来在每一次电梯while循环开始的时候都添加一句Thread.sleep(1);然后问题就解决了。看来自己对于多线程的知识还是不够熟悉。
结论:第三次作业相比于第二次作业,并没有在电梯本身的调度策略上或是架构上做出特别大的改变。大范围的更改主哟主要集中在对调度器的更改添加上面。通过调度器对多个线程进行操作和控制,基本上理解了多线程的相关知识.。
对于发现别人bug采用的策略
说实话,在这三次作业中,我只找到过别人一个bug。我自己对于发现别人bug采用的策略还是读代码,然后进行分析,看有可能在哪些地方会有问题。可能也因为此,我的找bug效率非常之低。可能是因为我真的不会写评测机吧。我觉得,对于多线程的调试,发现问题,想要找到问题可能并没有那么难...但是定位到问题的出处要花很长的时间。一般都会采用不停地插入打印语句的方法来寻找问题之所在。
总结
从总体上来说,我这三周的对于多线程的学习还是有不少的收获的。通过完成三次有关于电梯的作业,我大致上了解了多线程的设计思路、设计模式,以及有哪些需要特别注意的地方。在这几次作业之中,说实话,自己每一次都是不考虑性能分,完完全全按照指导书给出的建议和设计去完成所有的任务,因而也每一次都只能拿到2分左右的性能分。即使如此,还是完成的有些吃力,看来还是需要多加练习。但是所幸,自己在几次测试之中,因为没有经过优化,没有什么bug,最后也平平安安每一次都过来了。我觉得自己在接下来的学习中,要努力提高自己的课下测试能力,学习学习如何用程序进行自动的评测,自己因为只会手动输入,找不到问题的时候确实吃了不少苦头。希望可以在下一个单元付诸实践。