第二单元小结

第二单元作业总结

1.调度策略

①.傻瓜电梯

每次电梯只运送一个人,每一个请求处理完毕时再接入下一个请求。

②. ALS电梯

look算法。电梯在上下运行,并且发现电梯所移动的方向上不再有请求时立即改变运行方向。每到达一个楼层时判断是否有可捎带的请求。

③.多电梯

先将请求分为两个可执行请求。处理方法是:

  • 满足前提:拆分后的两个请求,fromFloor与toFloor隶属同一个电梯的可达楼层。
  • 在原始请求队列的时间上,拆分后该请求的三部电梯总时间最短。
  • 并对每个拆分请求的第二个请求置位,每当其第一个请求运行完毕才置位为真。

将分成的子请求分别加入到上行请求队列、下行请求队列。此时判断三部电梯所在楼层以及运行方向,优先选择运行方向一致且恰好可以捎带的电梯加入该请求;否则选择暂无乘客的电梯,由运行速度和楼层的总时间计算出优先者;否则选另一个方向,与上一步一致。最后才选择两个楼层均可达的电梯。(实际上大部分时间都靠这一条选择了运行电梯(……))

2.度量分析



第一次使用的类不多,但是在elevator类里的run()方法中,放了许多代码的具体实现,同时调用了很多其他方法,所以ev(G),iv(G),v(G)都比较大;因为外面是while(true)循环,平均循环复杂度也比较大。



第二次相对于第一次多加了inputhandler类和terminate类;其中inputhandler中addrequest方法因为有代码重复(没有再提取出一个函数…,所以ev(G)比较大;而在电梯类内部实现了许多循环和方法调用,平均循环复杂度和总循环复杂度都比较大。elevator类的代码量比较多,目前没有想到简化的方法。



相对于第二次多加了Monorequest类(继承了PersonRequest类)和request类(用来拆分Pr);request类里面的实现方法是暴力穷举+比较,重复率比较高,ev(G)、i(G)、v(G)都比较高orz。另外在scheduler类里面,要寻找合适的电梯,用了很多很多循环(。

3.线程安全

一共有两个线程,main线程与elevator线程。
同步互斥:直接在各个方法上加了synchronized关键字,虽然执行效率低,但是保证了安全。
线程的结束:
将调度器作为一个中间队列,没有单独开一个线程。调度器读入到null Request,继续输入到电梯内部。电梯一旦读入null request且内部无请求,打破run中的最外层循环。

一共有四个线程:main,scheduler,inputhandler,elevator。
同步互斥:将synchronized关键字转移到方法内部的某一块代码上。
线程的结束:
main函数中new了一个结束信号,这个信号同时传入scheduler,inputhandler和elevator。
inputHandler一旦读入到null request,跳出循环结束run方法,并将结束信号置位。scheduler当结束信号置位时结束线程;elevator则是当该结束信号为真且请求队列与乘客队列都为空时,结束线程。

一共有六个线程:main,scheduler,inputhandler,elevator1,elevator2,elevator3。
同步互斥:处理方法如第二次。
线程的结束:处理方法与②类似,唯一不同的是在最原始的请求队列在main中new出来,被六个线程都一块共享;在elevator的线程中并不对原始请求队列进行操作,只是观察到其为空且内部无乘客、置位信号为真时,停止线程。

4.工厂模式的碎碎念

对于作业中不同电梯的运行时间、可停靠楼层等状态,在elevator类的初始化中都当做参数输入了。之前师说把它传进去和把电梯传入调度器都是不好的设计,但是把不同类的电梯每次都写一个继承的话,然后生成不同type的电梯是不是对于本次作业太麻烦了。于是我选择了还是直接new三个电梯,然后加入到scheduler的电梯队列中……

5.错误点

不知道在写的时候会报错IllegalMonitorStateException,获得锁资源的才可以执行notify和wait方法,我的简单理解就是synchronized的对象必须是执行这两个方法的同一个。。这样下来,就不会出这个错了。。

线程安全问题。特别是第三次作业,出现了好几次有一个电梯的线程最后停不下来的情况。

捎带不上人,导致TLE。问题还是出在调度器中,加请求要等到所有请求输入完。

在第三次作业多个电梯中,学到了一个yield()方法,即可以让正在执行的线程暂停,但是不会进入阻塞状态,而是直接进入就绪状态。这样在三个电梯切换没有乘客退出循环的时候可以进入就绪状态,节省资源而且可以下一次请求直接来的时候转入执行状态。

6.总结

虽然这一单元的学习暂告一段落,但我还是不太明白怎么样高效的调试多线程程序,目前就只能在可能出现问题的地方直接print,貌似效率比较低……
或者是干瞪代码,确定一下哪些代码是多线程运行代码,然后找共享数据对应的哪些语句……

猜你喜欢

转载自www.cnblogs.com/maltose/p/10759244.html