OO第二次博客总结

1、 前言             多线程

  OO的复杂程度可能和写完的时间成正比,多项式时周三电工实习不带电脑,到了出租车已经发展成周三下午5点开始写Readme……不过相比前几回为语法耗费时间,出租车更多的是为设计来投入精力。多线程debug也颇有意思,在写多部电梯时,本身猛然发现调试时加入的一句System.out.println居然会对结果产生影响(过后才发现原来是输出调试信息到控制台耗费了时间,致使输出结束时其余线程的状态信息更新完成了,若不加输出,其余线程更新还没有完成,发生错误),真的迷……app

 

2、 多线程电梯        函数

    因为三部电梯的出现,想要让他们在三个线程中本身完成调度,就不得不在一个大请求队列的基础上,增长三个小的请求队列,分别存储三部电梯的请求。测试

  每当InputHandler有了新的合法请求,就拿到大队列的锁,将其加入到大队列中,叫醒调度器。一样的,每当电梯跑完当前主请求,也会叫醒调度器。调度器被叫醒后,要把当前大队列中的指令分给空电梯或能捎带的电梯,直至InputHandler线程结束且四个队列都为空,程序结束。优化

  

   此次虽然要求使用继承,但因为有捎带的但电梯写的并很差,索性直接重写Scheduler类。值得一提的是时间的处理。但电梯因为使用假时间,致使时间的计算冗余重复。本次是使用系统时间,相应的就带来了偏差,如因为程序运行致使的每层楼实际并非3000ms,实际上会多出几十毫秒。偏差的累计就致使了输入较多时,开始出现明显的时间偏差。所以我使用了消除偏差的方法,即在wait(3000)前,先计算所产生的偏差时间,将睡眠时间改成wait(3000-偏差),就使得时间彻底知足要求。spa

  与以前的问题大体相同,圈复杂度和嵌套深度过大。出现问题的carry方法是用来判断是否能够捎带,代码以下。线程

 1 /**
 2      * 查找是否可被捎带
 3      * @param request
 4      * @return 捎带返回true,不然返回false
 5      */
 6     public boolean carry(Request request) {
 8         if (request.get_flag() == 2) {// ER
 9              if (eleList[request.get_ele() - 1].get_status() == EleStatus.RUNNING) {
10                  if (eleList[request.get_ele() - 1].get_dir() == EleDir.UP && request.get_dstfloor() > eleList[request.get_ele() - 1].get_curflo()) {
11                      move(request, eleList[request.get_ele() - 1]);
13                      return true;
14                  }
15                  else if (eleList[request.get_ele() - 1].get_dir() == EleDir.DOWN && request.get_dstfloor() < eleList[request.get_ele() - 1].get_curflo()) {
16                      move(request, eleList[request.get_ele() - 1]);
17                      return true;
18                  }
19              }
20              return false;
21         }
22         else {// FR
24             int whichtocarry = 3, minsumdis = -1;
25             for (int j = 0; j < 3; j++) {
26                 if (eleList[j].get_status() == EleStatus.RUNNING) {
28                     if (eleList[j].get_dir() == EleDir.UP && request.get_dir() == 1 && request.get_dstfloor() > eleList[j].get_curflo() && request.get_dstfloor() <= eleList[j].get_dstflo()) {// bugwhere
29                         if (minsumdis == -1 || eleList[j].get_sumdis() < minsumdis) {
30                             minsumdis = eleList[j].get_sumdis();
31                             whichtocarry = j;
33                         }
34                     }
35                     else if (eleList[j].get_dir() == EleDir.DOWN && request.get_dir() == 2 && request.get_dstfloor() < eleList[j].get_curflo() && request.get_dstfloor() >= eleList[j].get_dstflo()) {
36                         if (minsumdis == -1 || eleList[j].get_sumdis() < minsumdis) {
37                             minsumdis = eleList[j].get_sumdis();
38                             whichtocarry = j;
39                         }
40                     }
41                 }
42             }
43             if (whichtocarry != 3) {
45                 move(request, eleList[whichtocarry]);
46                 return true;
47             }
48             return false;
49         }
50     }

  很差的一点是没用枚举而是以变量来表示状态,但因为捎带判断条件比较复杂,可能也很难优化了。另外一个圈复杂度高的方法是opendoor方法,用来输出,一样的,由于加入了时间的偏差消除,使得方法更加复杂,代码就不放了。debug

  bug方面,本身没有被报bug,可是测试的程序问题较多。如捎带没法判断、时间计算错误等问题,多是他没来得及调试致使的。设计

 

3、 IFTTT        3d

  本次做业是一个IFTTT的文件扫描。因为以前使用过相似的IFTTT类型app和坚果云这样的支持增量更新的云盘,因此我对这个思想并不陌生。不过因为本身的拖沓,致使了测试接口是在ddl前半小时写的,彻底没有调试,在被测时还有点担忧。

  本次因为要扫描文件,而文件的位置(路径)实际上包含在了文件的名字中,所以没有用到树来存储,而是使用HashMap<String, long>来存储,以文件的路径做为key,以其大小和最后修改时间做为value,对目录进行snopshot。以必定时间间隔更新snopshot,对监控文件进行查找和比对,若是触发则进行任务,不然继续扫描。

  我采用的是每条指令一个线程。在更新snopshot后,每条指令开始对其监控文件进行查找。所以就出现了一个问题:多条指令监控一个文件,有recover、detail、summary操做时,若recover先完成,极可能致使后二者没有被触发而未记录;recover后完成,极可能致使文件变化两次都被detail和summary捕捉到,记录了两次。这个问题是因为多线程的不肯定性致使的,所以不算作bug。但当互测时仍是被申报了,并且申报者说他解决这这个问题,我猜应该是将recover先不执行,保证必定触发两次。

 

  能够看到,Monitor类极可能成为了一个god类,其中的snopshot方法和compareFile方法彻底能够拿出来做为新的类。度量分析也印证了这个猜测:

 

  若是将这两个方法拿出来,状况会好不少。这是在设计上没有想好就直接写代码的结果。compareFile方法复杂的缘由,很大程度上是因为其中分了四种触发器,拆成四个函数会大大下降复杂度。

  此次做业因为分类树设置的很差,致使同源错误极可能被屡次挂树,如个人modified判断条条件画蛇添足的判断了大小,致使树上的detail、summary、监控文件、监控目录都挂了红……最后经过申诉解决了。我测试的代码一样出现了这个问题。除此以外,我已经屡次经过读手中最核心的运算部分的代码,找到了难以测试的bug,也反映出了读代码的好处。

 

4、 出租车        

  出租车即便给了写好的UI和map,也没有帮助测试……因为100辆车每200毫秒运动一次,很是难观察其运动的正确与否,不少时候当看到GUI能正常运行,就基本判断没什么bug了,所以读代码的重要性更加明显。

 

本次我才用了100个出租车1个线程的假多线程,InputHandler线程输入后,将请求发给Scheduler线程。Snopshot则将每200ms的位置快照发送给调度器。调度器根据位置搜索派单车辆,更新该车辆状态,而TaxiList则每200毫秒sleep一次,再让全部车移动,而后叫醒调度器进行调度。

 

  

  能够看到,许多方法出现了复杂度高的状况。因为车辆状态较多,到知道move等方法的复杂。

  我测试的代码,出现了一个问题。经过读他的代码发现,他在判断派单车辆时,将信用大于当前队列最优的车加入队列,此后从中选择距离最小的一个,而忘记把信用较小的删除。同时,个人代码中也有个问题。快照对于每一个位置的车辆,要用arraylist来存储,不然用int存其车辆编号,会致使同一位置有多辆车时,实际只存了1辆。

 

5、 心得体会        

  这三次多线程做业,让我从彻底不会多线程的使用,到对锁有了必定的理解,收获很大。可是熬夜更加严重了emmm……每周三还要赶一天工才能将将完成。活着真好……

相关文章
相关标签/搜索