北航OO第二单元——多线程电梯调度

北航OO第二单元——多线程电梯调度

前言

这次多线程单元可以说是很有挑战性的一个单元了,因为初次接触多线程这个神奇的操作,很多地方都感觉有些困难。但是在熟悉了操作之后还是很有意思的,de出了莫名其妙的bug也很有成就感。总的来说,还是收获满满的一个单元。接下来,我将总结这三次迭代中我的思路,分析一下我这次的策略以及debug的经历。

第一次作业

在这里插入图片描述

上边是我写的时序图(主线程负责启动所有线程)。可以看到第一次作业的要求是很简单的,指定了哪部电梯承载哪个乘客,所以我们只需要熟悉一下多线程的使用方法,掌握共享对象的上锁方法即可顺利完成这次内容。

这次设计我觉得我的可取之处在于将对于乘客队列的处理集中在RequestQueue中,而将Elevator线程只是当做只执行开门关门动作的类别,可以使代码更加有条理,同时Scheduler策略类集成在电梯线程内部,保证了策略修改时的可拓展性。

第二次作业

在这里插入图片描述

第二次作业相比第一次作业添加了reset命令和recerive命令,并且要求书写调度器,是我认为这三次代码修改量最多的一次。

第一个我认为需要着重讨论的是调度策略。很多大佬使用的影子电梯方法调度的,但是我觉得有点麻烦,而且确实能做到局部最优,但是并不能全局最优,所以我就自己简单写了一下调度策略。总的来说,是通过ElevatorTest作为储存电梯线程状态的托盘,由调度器获取。调度器先会找到wait的电梯,如何没有则找正在运行的同向电梯,即马上要经过请求楼层的,再没有则分给等待队列最少的电梯。当然这会有特殊情况,比如六十个人全部同向,我是直接设置了最大数量,保证相对平均。当然,最好还是做出缓冲队列,保证reset中的电梯也有分配的权利,不然五个reset就会造成巨大的时间开销。

第二个要说的就是线程结束的办法。因为我的reset策略就是将等待队列全都扔回RequestTable中,但是这样会造成一个问题,就是InputThread的结束并不能代表程序的结束,需要判断是不是还需要reset扔回。在我思考之后,想到了一个比较简单的策略,就是在RequestTable中添加一个记数的属性来记录输入线程传入了多少个reset命令,然后因为只要是reset,都会有一个扔回的过程,所以只需要在这个方法中添加一个null,也就是多扔回一个null,而RequestTable读到一个null就会记数减一,只有记数为0且输入线程结束时才会传出结束信号。保证了不会有reset命令的干扰。

这次说实话我也没有遇到啥值得提起的bug,只有一个我因为搞错了扔回和输出的顺序的小粗心(但是却挂了我8个点)。

第三次作业

可能是因为我前面写的还行,这次感觉没改多少原有代码,只是添加了ElevatorDouble这一表示双轿厢的新类和用于辅助的Flag类。

在这里插入图片描述

这次我觉的唯一值得一提的就是如何避免双轿厢相撞。我的策略是增加了一个Flag辅助类存储换乘楼层的状态,是不是有电梯占用。当双轿厢在换乘层的相邻层并要进入换乘层的时候,需要判断是不是有电梯占用换乘层,如果有,则等待它离开,没有则move。同时,如果一个电梯进入换乘层,那么它会将乘客放出来,放进来之后直接离开换乘层保证不会占用换乘层。

在这个基础上改一改策略类Scheduler中的方法,修改一下输出的方法我觉得就差不多了。

遇到的bug最经典的就是死锁了。我一开始以为会是因为一个轿厢占用Flag的锁,另一个占用RequestQueue的锁造成死锁,实际上并不是。是判断结束失败。双轿厢不仅要判断RequestQueue结束还要保证另一个轿厢中没有乘客,这是我错误的原因,加一个判断条件就好了。

最终代码分析

在这里插入图片描述

因为这次作业是多线程,java类之间并没有继承关系,而线程与托盘我在上文也介绍过了,所以我就不再赘述类之间的关系了,下面直接分析我的内聚耦合情况。

内聚耦合分析

在这里插入图片描述

可以看到在Distributor调度线程中,因为需要判断各种情况来分配,所以OCavg比较高,而在Scheduler中,由于需要根据各种情况来返回电梯的动作行为,所以OCavg也比较高,我把对于电梯队列乘客的操作集中在了RequestQueue中,所以方法比较多,我感觉都是正常的,逻辑也还行。

在这里插入图片描述

上图仅截取了复杂度较高的方法,可以看到调度器要判断情况来分配,所以逻辑复杂度比较高,简化也可以通过策略优化来实现,但其实其他方法我的实现还是比较好的,每个方法都比较明确。

debug方法

1.调试,适用于逻辑错误,比如某个数据的错误。

2.print大法。适用于死锁,轮询。print可以帮助你快速锁定哪里出了bug,然后可以肉眼看看有没有逻辑错误。主要是能保证结果差不多,不会像调试一样出现非调试的不同结果。

心得体会

g,然后可以肉眼看看有没有逻辑错误。主要是能保证结果差不多,不会像调试一样出现非调试的不同结果。

心得体会

那这次作业,我相对于之前的作业还是有了很大的进步的。一方面,我真正体会到了多线程的神奇之处,感觉很有意思。另一方面,我的代码风格上也有了进步,方法和类的功能更加集中,这使我的逻辑更加清晰,不仅仅更加容易Debug,还在迭代中更有优势。不足之处也是有的,就是调度算法还是没有做到极致,另外还没有尝试过更多的加锁方法,希望以后能够尝试一下吧。

  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值