这次的系列作业是写一个电梯调度,主要目的是让我们熟悉多线程。
第一次作业是一个傻瓜电梯的调度问题,要求也很简单,即每次接一个人就行了。我只用了两个线程,一个是输入线程,一个是电梯线程,输入线程负责从标准输入中读入请求并加入到请求队列中,电梯线程负责从请求队列中取出请求并执行,思路非常简单,每次取一个请求,把人送到后,再取下一个,直到取完并且输入停止。
第二次作业没有什么本质区别,只不过修改了调度算法,在电梯运行时进行捎带,我这里的思路是,先找到一个主请求,然后在去接主请求和送主请求去目的地的路上,每到一层先判断是否有人要出去,再判断是否能捎带,如果能加进来,不能继续走,这里还需要对开关门做一下判断,不能没到一层都开关门,有需求才去开门关门,然后还有一点就是对于这个捎带,每进来一个人,要加入到电梯队列,好在他需要出去的时候让他出去,同时还需要更新楼层,即当前是从5-10,进来一个从7-11的,那么目的楼层即变更为11,运行完毕后再去请求队列取下一个主请求。
第三次作业应该是最难的一次,因为涉及到3个电梯,对于这次作业我设计了5个线程,三个电梯线程,1个输入线程,1个调度线程,三个电梯线程本质和第二次作业一样,只不过增加了判断是否满员这一条件,以及输出时增加电梯编号,改一下一层运行时间就ok了,输入线程最为简单,输入进来就通知调度器,并加入队列,结束时改变调度器状态就ok了,主要说一下之前都没有过的调度线程。调度线程的用处是从请求队列中取出指令,判断是否需要拆分,并分配给合适的电梯这里我的思路是,如果他是一个一个电梯送不到的请求,则把他差分成fromflour->1,以及1->toflour,在这里需要注意,只有前半部分完成了,后半部分才可以开始,因此我们需要对此进行标记,每到一层当有人出去时,判断是不是拆分请求,如果是则把另一部分的标记去掉,让调度器可以去分配他;还有就是调度器的分配,当然是能一部电梯完成的就给这部电梯,但是当有多部电梯都能完成时,该怎么办呢?是给最快的还是电梯队列中人数最少的?我没有什么特别好的思路,因为我不会证明这两种哪个更快一些,比如当一共只有6个请求,A电梯和B电梯都能完成,这时候给全给A电梯肯定是最好的选择,但是如果有12个呢,那么平均分配一下是更快的,所以我还是采取了平均分配的策略,下面上一下第三次作业的方法参数图:
可以看出来,三个电梯类方法参数个数完全一样,只不过某些参数有些许不同,这样我们完全可以用一个类去写,多传一些参数进去即可,但是我却很笨的用了三个类,这也导致在debug的时候,需要发现一处问题要在三个类里修改,很容易忘记造成错误。
第一次作业可谓非常简单,基本上是两次过了,所以没什么bug,第二次作业我在写调度的时候出了一堆问题,无非是什么忘了更新楼层的问题,很好debug,主要说一下第三次作业。我第三次作业三个电梯所以写了三个类,其实完全可以用一个类,只更改一些参数即可,可是我却脑子一抽用了三个类,这就导致我在修改电梯代码时,改一个需要改三处,这就导致,有的时候会有忘改的地方,使得我最后强测错了,就是ac电梯改了,b电梯没改,80的强测分让人有点心痛,希望下次能不犯这样的错误。这里有个好消息是我的线程安全似乎没出什么问题,对于以后的多线程作业能有一个好的架构。
这里安利一个超级无敌的东西,评测机,用评测机去对拍bug可以发现很多线程安全的bug,交上去就是一发aoe,所以如此看来,也并没有什么策略一说,对拍真的是找bug效率最高的办法。(c组狼人都靠的这个,如果你觉得很不爽,一定要去学习一下怎么写哦)
最后是对这系列作业的一点点感想:我终于感觉到自己是在写java了,就像我上一篇说的,我在多项式求导中没有想出好的架构,最后直接一类到底莽下去了,其中各个方法完全是按照c语言的方法写的,这次作业则完全不一样,终于有了面向对象编程的感觉!
言归正传,线程安全是最重要的东西,因为你一旦线程不安全,bug不好测试,好不容易找到一个,又不好复现,而且不容易修复,所以在一开始设计时,就要想好架构,想好老师说的,共享数据一定要确保线程安全,还有架构的设计就是各个部分干各个部分的事情,这样比较好思考也好修复bug。