oo第二单元总结

                     oo第二单元总结

       在这一单元的学习中,我初次接触到了多线程程序的设计。让我感受到,一些任务是单线程程序很难完成的;而多线程程序,在线程并行的优势下,却也会引入更多的问题。就此展开了一系列练习的作业,从单电梯调度,可捎带调度,到最后多电梯调度的作业中,我也逐渐对线程间通信、同步与互斥的设计越来越清晰了。先分析一下这几次的作业吧。

一、作业的设计策略

1、第一次作业,设计了2个线程:

Elevator线程模拟电梯执行任务,Monitor线程负责监视并接受请求;

Request类的实例作为共享对象,存储了从Monitor接受到的请求队列,并给Elevator提供请求。两个线程在访问共享对象存请求、取请求时,进行同步控制。

2、第二次作业与第一次基本相同,多出Adjuster类,控制Elevator的具体调度。

3、第三次作业,实例化了3个电梯线程,为每个电梯实例化了1个request类,存该电梯应执行的请求队列;新增Control类进行电梯任务的平衡负载,将Monitor对象接受的请求及换乘后构造的新请求,分配到3个请求队列中,同时,判断所有任务是否都已执行完毕,控制所有线程结束。在control对象上新加同步控制,对于分配、结束状态改变、判定的方法进行同步控制。

二、基于度量分析程序

三次作业中Main类,都是作为启动用,构造好共享对象及线程,start线程后,就结束。

1、第一次作业

 

 

request类实例作为共享对象,monitor存,elevator取。

度量:复杂度不高,结构清晰;

2、第二次作业

 

 

新增的Adjuster类,类似于中介,把要执行的请求从request中取出,介绍给elevator

度量:复杂度不高,结构清晰。

3、第三次作业

 

 

新增control类进行全局控制,平衡分配任务,控制所有进程结束,及包括静态方法,控制电梯是否可停靠。

度量:复杂度不高,结构清晰。

三、分析自己的bug

1、第一次作业,未被发现bug

2、第二次作业,有严重bug,进行顺向捎带后,分配的逆向主任务会被忽略。

位置:Adjuster类中,findin方法。

原因:少考虑了一种情况,应加MainRequest!=null时,target = MainRequest.getFromFloor()

与多线程设计无关,实在是自己脑抽了没考虑全面,自己测试的时候,随便试了几下,觉得自己没bug,太不仔细了。

3、第三次作业,互测bug,电梯线程可能会提前结束,使换乘乘客请求无法送达。

       位置:Control类中,run方法

       原因:未判断三部电梯请求队列是否为空,只是三部电梯都无目标时就结束。

              一般情况下,三部电梯都无目标时,请求队列也会为空,考虑不全面。

四、发现bug策略

1、自己分类设计几类可能出错的情况,小规模数据手动测试。

2、浏览代码,对关键代码进行分析(比如同步控制语句),试图找到bug。

3、利用随机数据的评测机,进行重复、大量的测试。

与第一单元测试相比,多线程较难发现的bug主要是集中在线程安全问题上,而这些问题,在不仔细阅读分析代码前,是比较难进行重复稳定的复现的。使用评测程序,在重复、大量的测试集下,偶然可能会发现bug,但多数时间还是做着低效的重复工作。

五、心得体会

       多线程程序引入的线程安全问题,主要在于多个线程对于共享对象的读写、写写冲突。对于此类问题,可以采用上锁的方式,进行访问控制。例如,对一些方法或对象,修饰synchronized关键字,就可以简易的实现同时只有一个进程进入所修饰的代码块中;或是使用Lock实现读写锁等更灵活的锁操作;还有一些提供的线程安全类,比如AtomicInteger,BlockingQueue……,如此,对于x++,可以直接使用原子操作x.GetandIncrement,来实现线程的安全。

       在设计多线程程序时,应尽量减少线程对象间的直接交互;若是需要修改线程对象的某些数据,则应当提供一些public方法进行调用,而不是将这些数据直接交给其他线程修改。分析清楚需要进行同步的代码区,只在必要的同步代码块进行synchronized等同步语句的控制,来避免不必要的性能上的浪费。

原文地址:https://www.cnblogs.com/DengTC/p/10764296.html