北航OO第二单元总结
电梯调度的设计策略
第一次作业是单部多线程傻瓜电梯
这次作业的电梯名副其实是一部傻瓜电梯,每次只能运一个人。出于线程安全的考虑,选择了阻塞队列。然后按照先来先服务的原则服务下一个指令。没有什么复杂的设计方案,主要是了解多线程如何工作。由于觉得结构过于简单,没有分离出调度器的必要,就把调度器放在了电梯里,埋下了隐患。
第二次作业是单部多线程可捎带电梯
沿用了第一次的设计框架,把调度器仍然放在了电梯里,增加了指令队列的接口。采用的Look调度,相比于Search直观上好像变快了,但是对于精心构造的数据,Look还是会死得很惨(主要是是我的LOOK太菜了)。增加了电梯内指令(把指令队列分为了电梯外的和电梯内的,优先执行电梯内的队列,再执行电梯外的队列,可以优化,具体方案就是电梯在沿本方向的电梯外没有指令时才执行电梯内指令队列),以捎带的目的。
第三次作业是多部多线程智能电梯
试图沿用第二次的设计,并从原有电梯中继承子类。然而理想很丰满,现实很骨感,第三次作业未能成功实现。设计思路是这样的。就像下图显示的那样,黄色代表不能直达,绿色是建议的换乘的楼层。我们可以规定所有能直达的用能直达的电梯运算,不能直达的经过换乘层送达。由调度器把原有的请求队列from-to结构换成from-pass-to,当from和pass不同时,代表需要换乘,而from和pass相同时则代表无需换乘。但是实际遇到的问题是,需要换乘的情况174种,手动拆分工作量巨大,这个问题没有能处理掉。
基于度量的程序结构分析
第一次作业是单部多线程傻瓜电梯
很显然,第一次作业是不满足SRP原则的,电梯干了太多了工作,包括运输和调度。
扩展性还可以,尤其是请求队列,第二次作业中基本沿用。
尚未用到继承。
接口比较多,分工比较细致。
整体复杂度较低。
第二次作业是单部多线程可捎带电梯
第二次作业沿用了第一次作业的架构,所以也是不满足SRP原则的,但是一定程度上比第一次作业要清晰。电梯只接受方向和是否停留两个信号,而信号是来自队列自己的判读,也就是说,我把调度器放到了请求队列里面。
扩展性较好,如果只增加相同电梯的数量可以直接修改请求队列的分类,但是......第三次作业的电梯.......
尚未用到继承。
接口比较多,分工比较细致。
方向选择和是否停留需要遍历请求队列,复杂度较高,整体复杂度较低。
第三次作业是多部多线程智能电梯
第三次作业未能完成
BUG分析
第一次作业非常简单,在调试过程中遇到的bug主要是,在输入结束前判断队列为空。
第二次作业,首先是CPU空循环。如果不采用wait和notify的话,cpu运行时间会过长。
第三次作业,没有做出来。只设计了框架。
找别人的bug和自己的bug时,主要还是靠精心构造的数据莽。
心得体会
设计电梯的人真不容易,电梯还是买相同型号的比较好。
主要是掌握了生产者消费者的模式,了解了多线程是如何工作的,以及不得不面对的 线程安全 问题。
练习使用了一些线程安全的数据结构,也学习了如何使得线程不安全的数据结构线程安全。
在保证线程安全的同时,又要保证效率,比如synchronized的位置就很有讲究,不同的位置会引起效率上的巨大差别。
巩固了继承这一概念。