301
社区成员
发帖
与我相关
我的任务
分享
逐步变化:
waitQueue,Process 负责管理电梯的运行Queue 中引出两个子类:WaitQueue 与 ElevatorQueue,两者相同的属性 isEnd 与方法 setEnd 保留在 Queue 中,其他功能在子类中分别实现Process 中引出两个子类:NormalProcess 与 DoubleCarProcess,同样的,电梯最基础的运行功能保留在 Process 中,其他功能在子类中分别实现。此外,新增 Manager,用以监视、管理所有的实体对象,并负责乘客的分配未来扩展能力:
若新增不同运行策略的电梯,只要电梯自身属性没有改变,只需创造新的 Process 子类,用以管理该电梯的运行。值得注意的是,对于类似双轿厢电梯这样,电梯之间会相互影响的情况,需要谨慎考虑可能发生的线程安全问题。

稳定内容:
易变内容:
Schedule 中的分配策略Process 中的运行策略Schedule 与 Process 间的协调关系(如 reset 可能导致请求返回到 waitQueue 中)生产者与消费者的共享对象,为保证线程安全,几乎所有方法全部添加了 synchronized 关键字,因为它们都需要对队列进行读写操作。但 geAll() 例外,因为该方法在分配 request 时被调用,返回 queue 中的 request 个数,用以评估电梯的得分,是只读的且在数值上有一点偏差影响不大。也考虑过采用读写锁提高效率,但出现了不曾预料的线程安全问题,一时没找到原因,遂放弃。
在执行 DoubleCarReset 时,采用重置原电梯,并在 Monitor.elevators 中加入一个新电梯的方式。而在重置原电梯时,Schedule 还在不停的分配 request。为了避免可能发生的线程安全问题,将电梯的 initDC()(重置为双轿厢电梯时调用的方法)、evaluate() (分配 request 时评估电梯得分的方法)添加 synchronized 关键字,保证电梯不会在“变身”的途中被分配 request。
全部采用 synchronized 关键字很方便,但是相应的效率会降低。之后若有时间会尝试效率更高的锁。
双轿厢电梯有一个属性为 buddy,即同一井道内的另一个轿厢。电梯在移动前,会判断另一个轿厢是否停在自己的目标楼层。若是,则发出请求,使另一个轿厢离开;否则直接移动。
Elevator.initDC() 添加 synchronized 关键字后,bug 不再出现。(很好,又活过一个单元 (>_<)
在第五次作业中,对于线程安全问题还没有较为清晰的认知,只需要参考第四次实验,照葫芦画瓢即可。在第六次与第七次作业中可谓是受尽折磨,常常对 bug 原因百思不得其解,并怒斥电脑为何不能复现 bug …… 经过多个夜晚的冥思苦想,以及在纸上进行多次演练后,终于有所感悟
此外,对于电梯调度策略,随机分配似乎不失为一种有效的方法,并且不需要对电梯的当前状态进行读取。若想进一步提高性能,也可以根据一些参数(如电梯的运行速度)进行加权随机分配。想起自己写的愚蠢的分配算法,真是悔不当初。