BUAA OO第二次作业总结

OO第二单元总结

概况

第二单元的主要任务是模拟多线程实时电梯系统,第一次作业中,各个电梯之间没有任何联系。而在第二次作业和第三次作业中,由于我采用的是自由竞争策略,相同类型的电梯之间需要共享同一个候程队列,故各个电梯线程之间增加了协同处理关系。在第二次作业在第一次的基础之上中增加了横向电梯,故我们要增加一种新的调度策略以支持横向电梯的运行。第三次作业在第二次的基础之上增加了换乘的需要,故我们要修改调度器使之能正确的分配任务给电梯。

 

1.第一次作业

架构分析和调度器设计:

  在本次作业中,我的线程主要有main线程,输入线程,电梯线程以及调度器线程。其中输入线程接受输入的请求,将这些请求加入等待队列中,而调度器根据等待队列中的请求类型,将他们分配到相应的电梯的侯程队列中,在第一次的作业中,我们只需要考虑请求的起始楼座(其必等于终止楼座),将其分配给该楼座的电梯即可。输入线程的结束标志是输入的指令为空,调度器线程的结束标志是输入线程结束且等待队列中无请求,电梯线程的结束标志为调度器线程结束且电梯中没有人且该电梯对应的侯程队列为空。同时我们要注意轮询的问题,应该在正确的条件下使得相应的线程处于wait状态,避免其在本不需要占用CPU资源的情况下占用CPU资源。

同步块的设置和锁的选择:

  由于输入线程和调度器线程共用等待队列,故在对等待队列进行操作时,应该将对应的语句块上锁,其他对象均不是共享对象。在第一次的作业中,由于对锁还不是很了解,故采用的锁均为synchronized来进行同步。同时注意唤醒时要采用notifyAll而不是notify,否则有可能会造成死锁。

电梯内部的运行策略:

  这次的作业中我采用的是look算法,因为在这种来回跨度较大的楼座中,look算法相较于其他算法更加均衡,在随机数据中具有更好的性能。其主要思想如下,先朝一个方向运行,并在每一层中判断是否需要开门,在该运行方向上如果没有别的请求且电梯内已经没有乘客,则立即改变方向。

UML类图:

  

 

 

 

自己的bug:

  强测未出现bug,但互测被hack了很多次,原因是没有考虑输出线程的安全问题,即可能出现如下情况:

  1. 线程1获取当前时间戳
  2. 线程2获取当前时间戳
  3. 线程2将输出打印到控制台
  4. 线程1将输出打印到控制台

  这样就会使得输出的时间戳不递增,从而违背了题目要求。其实在指导书中特地强调了输出线程是不安全,需自行保障输出时间戳递增,但由于当时没有仔细深入的去思考这个问题,导致出现了这个本不应该出现的bug。

hack他人的策略:

  由于不会写评测机,我采用的是阅读他人的代码并自行构造一些数据,在这次的作业中,我看到了有同学在遍历过程中其原始数据有可能会发生改变,这样在多线程中有可能会报出ConcurrentModificationException的错误,于是我构造了一个在同一时间内突然进入很多相同请求的数据,hack成功。这个问题只需要将原来的数据类型有ArrayList改为CopyOnWriteArrayList即可。同时有一位同学从目的层到终止层时中间没有输出信息,比如从一楼到五楼,他在一楼和五楼进行了输出,这应该是评测机之前没有卡这个问题,不然肯定是进不了互测的,因为上一次hack别人时把这位同学给误刀了,因此我没有对这个bug再进行hack。

 

 

2.第二次作业

架构分析

  在整体架构方面,这次作业与上次作业并没有任何改变,只是在 上次完成的基础之上再增加了一个类,用以储存所有的侯程表队列,增加这个类的原因是上一次的作业中,由于所有的电梯线程在一开始就已经完全确定,故可以通过自己给电梯线程编号的方式来寻找相应的侯程队列,如A座对于下标0,B座对应下标1……。而在这次的作业中,由于在后续过程中可能会动态的增加电梯数量,因此无法通过提前编号的方式来寻找,因此在调度器的查询过程中需要遍历电梯线程的数组,这个数组就变成了共享变量(在输入线程中也需要使用这个数组),因此我为其建立了一个类以储存这些线程并在所有要用到的方法上加上了锁,如下面类图中的Queues所示。

 

 

调度策略

 

  这次的作业中,我采用的是自由竞争的调度策略,即当两个电梯属于同一类型(横向或纵向)且运行轨迹完全一致时,就让他们共享一个侯程队列,这样做的优点是总可以保证耗时最短的电梯可以接到请求,存在的问题是当一个请求需要被处理时,所有共享该队列的电梯均会往这个请求的方向运行,知道这个请求被接走,但我认为这并不是一个自由竞争严格意义上的缺点,因为其他电梯的移动并不一定会使电梯的最终的总运行时间变长。有可能这些移动恰好使响应下一个请求时所画的路径变短,虽然也有可能使得其变长,但从概率的角度上来看,我认为这个的概率是各占百分之五十的。因此没有必要花大量功夫去晚上这个问题。

 

同步块的设置和锁的选择:

  由于输入线程和调度器线程共用等待队列,故在对等待队列进行操作时,应该将对应的语句块上锁,另外,由于我采用的是自由竞争的方法,故电梯也有可能共享一个侯程队列,所以也应将相应的操作上锁。在这次锁的选择上,我选择的仍是synchronized,但这次我并没有将它直接加在方法上,因为有些操作其实是可以并行的,如果都加载函数上则会降低效率。我将将几种不能并行的函数上分别锁上了不同的对象。

 

 

调度器的设计

  与上次的调度器类似,调度器从总等待队列中取请求,然后根据请求的类型(横向请求or纵向请求),将其分配到合适的侯程队列中。

 

电梯内部的运行策略:

  纵向电梯沿用了上次作业中的look算法,同时做了一个优化,由于自由竞争时多个电梯可能会同时到达一个楼层进行接人,就可能会出现一个电梯开门但并没有人进来的情况,因为乘客可能都上了另一个电梯,为了防止这样的空开门的现象,我将开门、进人、出人看作一个原子块操作,即用synchronized将这几个操作锁住。横向电梯我采用的是ALS算法,因为不同于纵向的电梯,横向电梯每两个目的地之间最多所需的移动步数为二,我觉得look算法在这种小范围转移的运动中并不占优势,因此我对横向电梯采用了ALS算法,最后的性能分也是比较可观的。

 

UML类图:

自己的bug:

  强测出现了一个bug,因为一个地方复制粘贴的问题,将开门信息的输出粘贴在了到达信息的输出之前,导致会先开门再到达该楼层,所幸这个bug只在强测中错了一个点。互测被hack了很多次,均为上述原因。以后做题时一定要细心!!!

hack他人的策略:

  我采用的hack策略仍是阅读他人的代码并自行构造一些数据,在这次的作业中,我看到了有同学在判断电梯线程wait的时候使用的时if而不是while,而且他采用的时自由竞争的方式,侯程队列为共享对象。我推断这个地方可能存在轮询,因此利用了第五次作业的一个强测数据构造了一个相应数据,hack成功。

 

3.第三次作业

 

架构分析

  总体架构较上次基本不变,在上次的基础之上再增加了一个graph类,将电梯的运行速度构成边,最后可以将所有的电梯构成一张连通图。每次处理请求时都查询最短路径,同时返回最短路径给调度器以供调度器将请求分配给相应的侯程队列,我采取的是动态分配法,因此每次只需处理返回路径的第一部即可,当请求到达该步骤的重点时,如果还需继续换乘,就将其再放回总等待队列。这次作业和之前一个较大的区别就是结束逻辑的判断。这次作业中由于换乘请求的存在,因此不能简简单单的将等待队列的结束条件设置为输入结束且等待队列为空,这样会导致一些需要换乘请求还未回到等待队列时,等待队列就已经结束了。我在原来的基础上再加上了一个判断条件,每输入一个请求时,requestNum++,每完全处理完一个请求时,handleNum++,当这二者相等且之前的条件满足时,则等待队列的线程结束。

 

调度策略

  和上次完全相同,采用的仍是自由分配的方式。

 

同步块的设置和锁的选择:

  由于这次较上次作业没有增加共享对象,故这部分与上次作业完全相同

 

调度器的设计

  与上次的调度器有所不同,上次作业的调度器直接处理请求,直接根据请求的类型以及起始楼座、终止楼座、起始楼层、终止楼层等信息将请求进行分配。而这次的因为有换乘请求的出现,因此要先将其放入Graph类的getMinPath方法中获取路径,调度器直接处理的是总路径的第一条路径,根据返回的第一条路径来决定该请求应该被放入哪个侯程队列中。

 

电梯内部的运行策略:

  和上次作业的运行策略完全相同

 

UML类图

 

 

自己的bug:

  强测出现了一个bug,原因在很极端的情况下可能造成超载。互测没有被hack。

hack他人的策略:

  我采用的hack策略仍是阅读他人的代码并自行构造一些数据,在这次的作业中,我看到了有同学调度器的设计中只考虑了要换乘的请求而不用换乘的请求没有考虑全面,我设计了相应测试点并成功hack。

 

 

心得体会

 

1.多线程的线程安全问题:

  当存在共享变量时,我们一定要注意相应的方法时候需要上锁,而且在上锁时尽量使用合理的锁,如读写锁。同时若存在嵌套锁,一定要保证锁的顺序是一致的,以避免死锁的产生。

2.轮询问题:

  在判断线程是否需要wait的时候,一定要将条件判断完全正确,否则极有可能造成轮询或者在不该wait的时候进行了wait。

3.架构问题:

  良好的架构是我们写出优秀的代码的必要条件。在这方面我还应该不断提高,还需要不断去了解各种好的设计模式和架构。

 

posted @ 2022-04-27 21:37  郑凯荠  阅读(26)  评论(0编辑  收藏  举报