301
社区成员
发帖
与我相关
我的任务
分享该电梯系统是一个类似北京航空航天大学新主楼的电梯系统,楼座内有多部电梯,电梯可以在楼座内1-11层之间运行。系统从标准输入中读入乘客请求信息(起点层,终点楼层),请求调度器会根据此时电梯运行情况(电梯所在楼层,运行方向等)将乘客请求合理分配给某部电梯,然后被分配请求的电梯会经过上下行,开关门,乘客进入/离开电梯等动作将乘客从起点层运送到终点层。
可以采用任何电梯运行策略,即任意时刻,系统选择上下行动,是否在某层开关门都可以自定义,只要保证在电梯系统运行时间不超过题目要求时间上限的前提下将所有的乘客送至目的地即可。
乘客乘坐给定编号的电梯,不需要自行分配电梯
不指定乘客所乘坐的电梯,由设计者进行电梯调度,新增Reset请求,改变电梯最大载客人数和移动速度,Reset需要一定时间,期间电梯要求内部没有人且关门,即在两次楼层移动内将电梯内所有人员移出,同时对请求响应时间增加限制
新增双轿厢电梯,将一部电梯分裂为上下两个,各自只能在自己的区域间移动,不能同时处于换乘楼层
同步块的设置和锁的选择
在本单元中,线程安全是最核心的课题。对于共享读写资源,我们可以使用synchronized关键字进行同步块的设置,对其上锁。经过分析,共享资源主要包括待分配请求池、请求总池、电梯线程,因此同步块大量设置在RequestQueue类中。需要注意的是,并非所有同步块中都需要notify操作,这将由设计者决定,盲目地增加notify将导致不必要的唤醒。
与此同时,调度器在将待分配请求分配至电梯线程时也需要注意线程安全问题,需要先拿取到电梯线程的锁再进行分配,以防出现电梯重置与分配乘客相关问题。
第三次作业中是如何实现双轿厢的两个轿厢不碰撞
在第三次作业中,出现了”换乘层“这一概念。出于线程安全问题考虑,我们需要对该层设置占领锁。当轿厢进入换乘层时,拿取占领锁,使其余轿厢无法进行换乘层。当轿厢离开换乘层,放开占领锁,使其余轿厢可以通过拿取空置的占领锁进入换乘层,从而避免轿厢碰撞问题。
值得注意的是,当我们采用该方法时,一定需要将同一电梯井的轿厢设置为并行线程执行而非同一电梯井动作中的顺序执行,否则必然会因换乘层的问题卡住程序,导致RTLE。
总结分析三次作业中的调度器设计,并分析调度器如何与程序中的线程进行交互;总结分析三次作业中的调度策略,并分析自己的调度策略是如何适应时间、电量等多个性能指标的
调度是本单元作业很重要的一大部分,直接体现电梯运行策略。
在第一次作业中,我们不需要考虑调度,请求按照电梯Id分配。从第二次作业开始,我们就需要认真考虑不同调度策略的性价比——编程难度、性能表现、提升空间、可扩展性等。
需要注意的,对于三次作业的强测及以下内容来说,类似于影子电梯、权重打分等调度策略的优势被削弱了,这是由于即使是强测内容,其压力强度也远不能使以上策略较Random策略有较大幅度的性能提升。根据周围同学的体验,设计较复杂策略时,调度器与电梯线程的双向通信中线程安全问题频发。有鉴于此,Random均匀分配不失为合适的策略——但Random方式需要进行设计,以免互测时被Hack过狠。
三次作业架构设计的逐步变化和未来扩展能力

值得一提的是,三次作业架构基本没有变化,得益于从第一次作业开始设计时就使电梯线程ElevatorThread中包含了电梯类Elevator与策略类Strategy,为未来两次作业保留了良好的可拓展性。
第二次作业只是在电梯类中增加了Reset操作,在电梯线程中增加了应对Reset请求的处理方法。
第三次作业中鉴于规模不大,没有采用工厂模式,只是在电梯线程中预留了一个未实例化的电梯类对象,一旦接收到DCReset请求就将其实例化,与原本已实例化的电梯分别作为A、B轿厢进行运行。
分析bug及心得体会
本单元的bug主要体现在线程安全方面。面对多线程程序,idea自带的断点调试方法已经不再可靠,因此在本单元中我均采用print输出程序信息的方法进行调试与debug,在重要的拿取、放开锁节点要求程序进行当前必要信息的输出,从而清晰地观察多线程的运行动向,知晓具体线程安全问题的产生点,效果显著。
本单元中令人印象深刻的bug有以下几种:
电梯重置与分配乘客的冲突,导致乘客receive信息重复输出或失踪;
换乘层死锁;
第一次作业中开关门概念误解;
最后再分享一点心得体会,第二单元的作业难点在于线程安全总是感觉难以得到保障,但在经历过不断改bug之后,不仅对线程安全的理解更加深入了,还丰富了自己修改bug的能力。这一单元经历了被刀,体会到改bug的不易,收获满满。