oo第二次博客总结
多线程的技术分析与梳理
一、对三次作业推荐的设计结构:
1、第五次作业:
线程对象:请求模拟器(InputThread)、调度器(Scheduler)、三部电梯(ER1、ER2、ER3)
共享对象: InputThread与Scheduler之间共享主请求队列 (生产者-消费者)
Scheduler 与 ER1共享ER1的请求队列 (生产者-消费者)
Scheduler 与其他两部电梯的共享方式与ER1的相同
线程协作关系: InputThread采取主动模式,不断监视控制台的变化并读入请求
Scheduler与 ER1、ER2、ER3均采取被动模式,当各自的请求队列 发生变化时做出相应的改变
同步关系: InputThread与Scheduler在共享主请求队列时互斥
Scheduler在与其他三部电梯共享其各自的请求队列时互斥
(读的时候不允许写,写的时候不允许读)
2、第六次作业:
线程对象: 每个工作区分配一个获取快照线程、一个快照diff线程和一个触发控制
线程; 测试者线程对象
共享对象: 所有线程共享summary对象、detaile对象
同一个工作区之间:
获取快照线程与快照diff线程共享生成的快照
快照diff线程与触发控制线程共享触发控制信号
不同工作区之间:共享重叠部分的文件对象
线程协作关系:
在同一个工作区内的线程间存在协作关系:
获取快照线程采取主动模式,每隔一段时间生成一次快照
快照diff线程采取被动模式,每当新的快照传入就开始进行比较
触发控制线程采取被动模式,根据快照diff线程传来的信号进行工作
同步关系: 所有线程对summary对象方法的调用之间互斥
所有线程对detail对象方法的调用之间互斥
同一工作区中:
获取快照线程与快照diff线程对快照的读写互斥
不同工作区中:
对重叠部分相同文件的访问之间存在互斥
3、第七次作业:
线程对象: 请求输入线程、出租车线程、中央调度线程、抢票窗口线程
共享对象: 请求输入线程与中央调度线程之间共享请求数据对象
中央调度线程与抢票窗口线程之间共享请求数据对象
中央调度线程与抢票窗口线程之间共享所有出租车对象
中央调度线程与出租车线程之间共享出租车对象
中央调度线程与出租车线程之间共享地图对象
线程协作关系:
请求输入线程为主动模式,负责监视控制台的变化并读入请求
中央调度线程为被动模式,根据读入的请求开启抢票窗口线程
抢票窗口线程为被动模式,由中央调度线程负责开启
出租车线程为被动模式,根据抢票窗口分配给自己的请求进行响应
同步关系:
中央调度线程与请求输入线程在读写请求队列时互斥
中央调度线程与出租车线程在读写出租车数据时互斥
抢票窗口线程与中央调度线程在读写出租车数据时互斥
二、自己程序的设计结构:
1、第五次作业:
(1)类图:
(2)线程协作示意图:(由于主线程只负责开启线程并传递共享对象因此并未画出)
(2)优点:整体结构较为清晰。
缺点:没加锁,当时并没有考虑太多。实际上分析,之所以没有出现丢指令的原因 在于请求队列的生产者和消费者都仅有一个(InputThread 和 AllocThread),这 样在读的时候首先判断是否为空,所换来的最坏情况也就是size改变而导致在 这一次循环遍历运行中没有把新加的请求分配而将其留到下一轮而已,而且由 于只有一个消费者所以并不会出现请求队列为空还在取的情况。或者在for循 环时产生中断,由于每次循环都是判断i < ....size(),时时判断其最新长度所以 并不会将新加入的请求留到下一轮。总之在这次侥幸没有出现线程安全相关的 问题完全是仅仅只有一个生产者和消费者。
2、第六次作业:
(1)类图:
(2)线程协作示意图:
(3)优点:将File类改装成了一个线程安全(所有方法都加了synchronized限制)类,在 工程中的所有File对象都升级为了FileOperate对象,保证了对同一个File的操 作是安全的。
缺点:锁太重,直接对方法无脑加锁会导致运行的效率低下,尤其是在上锁的方法 中还进行了控制台的输出。
3、第七次作业:
(1)类图:
(2)线程协作示意图:(由于主线程只负责开启线程并传递共享对象因此并未画出)
(3)优点:使用synchronized修饰代码块而不是方法,尽量缩小了被锁住的代码块的规模以及可能的运行时间,基本杜绝了上锁代码块中对控制台的输出以及其他与锁无关的操作。
缺点:依然存在在上锁的代码块中对文件的输出操作,而且在每次的抢票窗口结束 进行最终分配时要锁住所有的出租车,从而导致不断累积下来会产生运行的时间误 差。
三、自己程序的BUG:
1、第五次作业:
对FR同质请求的处理未能输出same
原因:在进行同质判断的时候只考虑了ER的请求同质而忽略了FR请求的同质判断
2、第六次作业: 未被发现
四、别人程序的BUG:
均未发现BUG
五、心得体会
(1)分析指导书的需求,明确所需要开启的线程。基本的常用套路为一个线程负责监控 外部命令,将信息传达给中央共享的对象,之后其余的线程共享这一个对象,进行分析 与操作,再使用另一个线程负责完成相应规格的输出。
(2)明确上锁的对象和使用的区域,减小被锁对象的大小以及被锁代码块内的执行时间。 当仅仅需要在对一个对象的某一个属性进行保护时锁住该属性即可而不必要锁住整个 对象,这样其他线程对该共享对象的其他属性的访问和操作也可以正常执行。尽量避免 在synchronized代码块中与控制台、文件的交互,这样的话容易阻塞其他线程的运行, 降低了程序的并发性能