其他分享
首页 > 其他分享> > OO第二单元总结

OO第二单元总结

作者:互联网

第一次作业

设计策略

第一次写多线程,对于多线程还不够了解。导致第一次作业的结构非常奇怪(不好),占用大量线程资源,也完全没有可拓展性,可以说完全不是一个合格的多线程程序。第一次不知道如何写队列,所以没来一个request我就会为其创建一个进程,并且直接进行put访问。对于托盘中,将put和get方法全部上锁,而且托盘有且只能放一个元素,所以如果托盘是满的时候会对request全部阻塞。这样的写法不会有语法的错误。

电梯也没有自己的线程,而是每一次都通过people线程调用,所以电梯传给了每一个people类。

main函数:
divider.put(new Person(request));
people类:
public void run() {
       try {
           elevator.handleRequst(fromFloor, toFloor, personId);
      } catch (Exception e) {
          ;
      }
  }

但是也是有问题的,首先这样会创建过多不必要的线程,占用大量cpu资源。再者,这样对电梯非常不友好。当电梯在被阻塞的时候,每一个notifyall会唤醒所有的等待进程。如果再等待的request进程过多的话,电梯需要竞争到锁将会非常困难。也是会使整个cpu减速。第三,其实这样的写法并不符合指导书要求的先进先出的功能。因为线程竞争锁的时候是无序的,所以并不能知道是哪个request竞争到了锁。

所以第一次写得并不好,唯一的好处可能就是写得十分简短,不到80行就解决了全部的问题(笑)。后来在互测的时候,我通过阅读别人的代码了解了一个真正的多线程应该要怎么写。

类图&度量分析

           

可以看见类之间的联系甚至类方法和变量相对是简单(粗暴)的,问题并不在于类关联上。换句话说是在第一单元的练习中,我们已经逐渐了解了一个好的java设计应该是什么样子的。

bug分析&debug

这一次因为不到80行的算法因为设计过于简单粗暴,所以没有出现大的bug。强测没有出现,互测屋里面也没有人有bug。但是我通过阅读互测屋中其他同学的代码也学到了很多值得借鉴的方法。

第二次作业

设计策略

这一次电梯增加了捎带。我的多线程设计也有了明显的改进。这一次我将电梯设计成了一个单独的线程,方便第三次作业中多电梯的拓展。并且在调度器中增加了等待队列,取消了每个request的线程。调度器中的get和put方法以及新增的处理捎带的方法supplement都是用synchronized上锁的。

当request到来的时候由main线程将request推给调度器。这次是一旦竞争到了锁将会直接保存在等待队列内。而电梯将会在空闲的时候主动访问调度器寻求request,如果等待队列为空,则waiting,等待request来的时候被唤醒。此时得到的request称之为主请求。对于捎带的处理时,每一次电梯sleep完一段时间之后都会主动访问调度器的捎带方法supplement。调度器将根据电梯当前楼层和方向传回等待队列中可被捎带的请求。

而为了防止 “1-FROM-2-10 / 2-FROM-1-3 / 3-FROM-10-2” 这样的魔鬼数据的存在,我的电梯将会模拟真实电梯的调度算法,即不是严格的先进先处理。而是每一趟的方向都不一样,即电梯到了本站终点后,不论当前等待队列第一请求是什么方向的,都会进行转向。只有在反方向没有请求的时候才会继续处理同向请求。

因为这一次加上了ARRIVAL的输出,所以sleep函数是每一层一停的,这样我访问捎带方法也更加频繁,可以尽可能的捎带上所有的请求。

类图&度量分析

  

 

这一次各个类的关联度就比第一次作业多很多了,甚至elevator.run类都超出红线了。原因可能是这次的输出信息较多,不同的数据存储在不同的类里面,所以数据就被传来传去了。比如当我们要判断是否可捎带的时候需要对可等待队列进行遍历。但是每个request的起始楼层和方向都存储在request的类中,而非调度器类。所以调度器需要不停的访问request类。

第二,我的elevator.run可能承载了过多的功能,基本模拟了全部的电梯运行过程,而且有一部分代码重复,设计出现了不是很合理的地方。

bug分析

这次我的代码在强测和互测中出现了一个bug,虽然只是两行的问题,但是它成功的让我的强测炸了。bug出现的原因还是在于我在课下自己测的时候并没有完备的问题。

原理很简单:(错误代码)

private void moveOneFloor(int floor) {
       if (floor != 3) {
           mySleep();//访问捎带方法
           atFloor = floor;
           TimableOutput.println("ARRIVE-" + (floor - 3));
      }
  }

在电梯运行一层之后的时候,我是先进行的捎带询问,再更新的楼层。就是这两行的顺序错了,导致我的电梯运行一段时间后,已经到了下一层,但还是能捎带上刚刚到的还在上一层乘客。

在我自己测试的时候,我没有进行很多这种关于时间差的测试,而是把重点放在了指令的楼层选择上,很多时候指令都是一起输入进去的,所以并没有测出来这个bug。

第三次作业

设计策略

第三次作业我是在第二次作业上进行的改动,总体的调度以及捎带策略没有发生大的改变。关于电梯运行速度,承载人数的变化就只需要改变电梯类,增加相应的成员变量即可。

发生了较大改变的是调度器这一块。因为有三台电梯,每个电梯能够执行的请求又互不相同,而且存在换乘的情况。新增加了一个队列类,为每一个电梯都保存一个请求等待队列。当一个request到来的时候,调度器会先判断请求是否需要拆分,如果不需要的话就将请求保存到可以执行它的电梯的队列里面去。每当一个电梯来取指令,就在自己的队列里面寻找合适的请求。每取走一个请求都遍历一遍所有电梯的等待队列,删去所有相同id的请求,即相同请求。

对于需要换乘的请求,在请求输入到调度器时就进行切分。将前一条指令正常输入到电梯等待队列中,后一条指令加入wait队列中。电梯每一次完成一条指令都去wait指令中寻找是否有相同id的指令,如果有则将该指令再加入电梯,这样就实现了切分。

类图&度量分析

   

因为继承了上一个Project的Elevator的绝大多数方法,所以elevator.run依旧很复杂。其余的方法还好。因为这次的条件很复杂,所以成员变量以及方法都很多。

优化

这次我将三个电梯的队列都写在了同一个类里面,三个电梯能够搭载的楼层也是写死在了一个类里面。如果要优化结构的话,我会将三个电梯分成三个不同的调度队列类,并将有关的数据在创建类的时候传输进去。

bug分析

这一次也是有一个简单到弱智的bug(并不)。让我的强测炸了并且在互测中被hack了十几个点。但其实总共也只错了三行...原因就是我过了弱中测之后就再也没有自己测试过了。我的错误在于电梯人数更新不及时,更新错误,导致电梯超载等一系列玄学问题。

r第2、3次作业debug

本次debug因为输入输出都非常的复杂,所以采用的是自动化的测评与阅读代码相结合的方式。

与第一次作业有所不同的是,在第一次作业中,我们只需要考虑输入的数据问题,而在这一次中,输入的时间也是考虑的因素。有可能两组相同的输入因为时间不一样而导致完全不同的结果。所以更加需要自动化的测评,包括生成数据,统一测评和结果分析。如果没有的话,一个人会测到天黑看结果看到眼睛疼的。

体会与心得

 首先多线程问题在这三次作业当中有了一个逐步的摸索与尝试。了解了基本的线程知识,会写简单的多线程程序,也知道了什么样的是一个好的多线程结构(第一次作业的血的教训)。通过对多线程的学习也成功做出来了课上上机题目(巨大的飞跃(雾)

再者感受到了自己测试的重要性,自己不测一时爽,强测分数火葬场。

 

标签:OO,总结,队列,request,调度,捎带,电梯,多线程,单元
来源: https://www.cnblogs.com/lxy17373300/p/10756766.html