OO第二次博客作业
第五次作业:多电梯调度
这是我第一次接触多线程编程,因为写之前一次电梯捎带处理的作业时用循环模拟了一个时间系统,这一次直接使用真实时间代替模拟时间,所有处理的流程都只需要按照自然发生的顺序,反而简化了我很多逻辑。但是从多线程的角度,我很多基本的概念还是存在理解问题。



这次作业我构造了请求输入处理、调度器和三部电梯这几个线程,主要的设计策略是输入处理和调度器共享一个待处理的请求队列,三部电梯各自管理自己内部的执行队列。这样一来,只要总的请求队列不为空,调度器就不停地取出其中的请求,先判断其类型,是电梯类的就直接分配给相应的电梯,是楼层类的就按照指导书的要求判断要分配给哪部电梯。
有些哭笑不得的是,公测和互测中被测出的全是粗心大意的格式问题(可能是太过畏惧多线程而忽略了基本的东西……),也没什么可分析的,但撇开这些不说,虽然表面上功能都没问题,我还是反省出了很多实现细节上的毛病。
首先还是分工上的不合理,我把判断捎带这一块的逻辑全部放到了电梯里。按理说各个电梯应该只在一次处理当中提供各自的状态缩影,让调度器来决定谁去捎。由于我在时间上做了点手脚所以输出看起来没毛病,但实际上线程都是各跑各的,每次的判断也都是基于自己的实时状态,整个系统在逻辑上并没有一个统一的时间,调度器也不是每次都刷新他所管理的电梯状态。
时间上的混乱还存在于线程sleep的问题,其实按照电梯运行速度和调度周期来唤醒线程应该是比较合理的处理方法,但我当时完全没有这个概念,导致一个周期内的while函数进行了很多次没必要的循环,只是线程数少所以效率上还没有很明显的体现。
其次就是线程安全问题,我后来才知道Vector是线程安全的,而我使用的ArrayList不是。这一次涉及到共享的对象主要是总的请求输入和处理的队列,以及每个电梯内部的执行队列,但我只给前者加了synchronized锁,当时对于这个锁加在哪儿具体是锁了什么东西也不是很清楚。
再有就是电梯直接实例化了三部,既没放到队列里也没向调度器注册,正是老师说的最糟糕的设计情况。请求输入的判断直接在run函数里展开了,也很不规范。
第六次作业:文件监控
虽然我第一次多线程写的很不规范,但第一次让我真的为线程并发困扰的是第六次作业。



我的主要设计策略是构建一个触发器的类,几种不同的触发器分别向父类继承。触发器实现了Runnable接口,每个周期内扫描监控范围存取文件快照(我自己定义了一个数据结构),然后比对两次扫描的结果,调用子类的具体比对方法,来判断文件是否有要求的改变,再产生相应的结果。
公测出了两个问题,一个是无法忽略相同输入,这是一个“equals”方法的坑。原来只有在String对象中,equals才会比对实际的值,而一般的Object如果不进行重写,都只会比对引用对象是否相同,所以相当于是白写了一句话。另一个问题是重命名恢复的时候触发器会自己检测到这一动作,然后不停地报出重命名行为。这是因为进行恢复之后,没有更新本次扫描的快照,导致下一次的比对有检测出不同,属于我的设计缺陷。互测出的问题是文件被移动后其监控范围没有缩小,其实我也定义了相关的更新方法,但是在单个文件移动时忘了调用该方法,其实是自己细节上测试不全的问题。
关于多项程,这次作业给了我两个启发。一是让我终于有了一个周期内提取对象主要信息的概念,也就是存快照,而不是直接实时地去取对象的状态来用,这样很容易发生一些随机的问题;二是线程安全很多时候还出在几段代码的逻辑顺序上,对单个对象的某个方法加了synchronized锁,但是把这些方法放在一段代码中执行,方法与方法之间还是会被打断,继而出现问题。此外,针对这次作业,我并没有太认真考虑文件夹层次复杂的情况,每一个输入就只开了一个线程,虽然测试没测出什么问题,但事实上规模太大的文件夹可能递归起来会很慢,单个线程使用的扫描时间会很长,并不是一个很好的设计。
第七次作业:第一次出租车调度
这是最近的一次作业,我感觉也是比较复杂的一次,之前出过的所有问题都能在这一次暴露出来。



我为每辆出租车开了一个线程,负责调度的服务器作为一个线程,输入处理开了一个线程。和电梯调度一样,调度器取出请求,分配给适合的出租车,有了前两次作业的经验,这次我在每个调度周期开始时获得出租车的状态,也给访问和修改状态相关的部分加了锁,出租车负责处理自己当前的乘客请求,更新自身的状态,并记录行驶路线。
公测和互测还是测出了输入的问题,一是没有判断起始相同的请求,二是不能判断同一时刻的相同请求,都属于设计时忽略了这两种情况。互测的同学非常认真,还发现了我一个设计逻辑上的问题,出租车在到达客人所在位置时多停顿了200ms,这应该是状态改变的内部逻辑上先后顺序有问题导致的,而我自己测试的时候竟然也没有发现这一问题。
关于测试:
由于多线程的不确定性,我在测试别人的时候有些不知从何入手。电梯调度作业中,我用可能会出现问题的请求组合发现了同学在判断同质上和捎带上的问题;文件监测作业也找到了被测同学输出和不能检测范围上存在的bug;但出租车调度我测的并不是很仔细,一方面是不太清楚测试代码的编写要从何入手,另一方面是自己构造的测试集也很不全面,所以只找出了文件输出表面上的几个逻辑问题。
心得体会:
多线程确实不同于以往我们接触的编程,要注意的细节很多,我自己每次出的问题也都是在一些细节没有考虑周全上。通过这三次的作业,我对线程安全有了一定的了解,大概知道了对象加锁,静态方法加锁和非静态方法加锁的区别,但是运用还不是很熟练。总体上感觉测试还是很重要,这几次因为把重心全部放在要怎么构造多线程上,反倒忽略了功能上全面的测试,设计思路上的问题暂且不说,一些基本的预处理上老是出问题实在是不应该。我今后的方向应该是然自己更认真细致,多深究一些问题,不能总是得过且过。

浙公网安备 33010602011771号