第五次做业——多线程电梯安全
设计策略多线程
实现三部电梯的综合调度,为每一个对象线程明确任务分工。对象线程间经过发送睡眠中断信号实现事件通讯。并发
Presser对象不断读取请求模拟按下按钮,生成请求并发送至请求队列中并向调度器发送新请求到达的中断信号。测试
电梯对象拥有一个任务执行队列,经过不断检查系统时间是否已到任务结束的假时间戳模拟执行这个任务队列完成请求,该任务队列由调度器负责添加新任务。电梯若执行完主请求,则暂停运行并向调度器发送中断信号请求分配任务。编码
调度器对象接收到中断信号后,尝试到请求队列中获取新请求,并获取三个电梯的状态分配请求,更新电梯的任务队列。spa
访问冲突存在于两个地方,一是调度器与Presser对象读写请求队列,而是调度器与电梯读写任务队列。那么就须要请求队列与电梯加锁。线程
度量分析设计
代码分析3d
类图对象
协做图
bug分析
次此做业没有什么大问题,互测中发现别人的程序在模拟电梯运行中直接使用真实时间模拟运行,致使由于线程调度存在阻塞,出现了累积偏差,运行一段时间后,电梯的到达时刻会有0.1秒的正偏差。在个人设计中使用的真时间模拟假时间戳,能够消弭这样线程运行调度引发的累积偏差。
第六次做业——IFTTT
设计策略
监控文件系统的修改状况,一个监控对象的一种修改状况,对应设立一个触发器线程,触发器下可吊挂多个效应器。
每一个触发器线程轮询文件系统,比对新旧快照,判断触发条件,若触发则启动该触发器下挂的效应器。
访问冲突在于触发器要读文件系统,效应器可能要写文件系统,那么为文件系统加锁,简单的synchronized悲观锁会互斥任何针对文件系统的操做,但其实咱们但愿的是,多个读者间是不互斥的,只有读写者、写写者间保持互斥,这种加锁方式比较复杂,须要用到闸机模型,当时也不知道闸机模型,因此仍是用的synchronized锁。
度量分析
代码分析
类图
协做图
bug分析
这次做业没有什么大问题
第七次做业——模拟出租车
设计策略
模拟100辆出租车载客运行。设计彻底模拟现实生活中的场景,为每一个对象作明确合理分工,各作各事。
InputerHandler对象负责读取请求并将请求发送至请求队列。
调度器对象负责从请求队列中获取新请求,并为每一个新请求生成车辆抢单用的报名表,挂靠在地图上的相应的请求出发结点上,供过往的出租车抢单报名。抢单窗口关闭后,根据报名表上登记的抢单车辆信息和其目前的状态,为请求分配车辆。
出租车的任务是在城里闲逛,并查看附近地图结点下挂靠的抢单报名表,参与抢单填写本车信息,等待派单。如成功抢单,则执行送客任务。送客结束后重复上诉操做。
访问冲突在于调度器要在地图节点下发放和收取报名表,出租车要在地图节点下查看和填写报名报,所以为地图上的每个结点加访问锁。
度量分析
代码分析
类图
协做图
bug分析
这一次程序在总体设计上没有什么大问题,只是出现了两个由于粗心致使的小bug。测试对面的程序时再一次出现了相似第5次做业的时间偏差问题,被测程序直接使用真实时间模拟出租车的运行,由于线程调度的问题,有的车的运行时间就开始出现累积偏差了。
心得体会
资源访问的安全问题是多线程设计的重要问题之一,在最初的设计过程当中,就要作细致的分析和全面的考虑。首先要研究每个对象的读写行为,寻找对象间的读写冲突点,并要根据不一样到的读写特征选择适当的加锁方式,以免过多的线程阻塞致使的效率降低,而不是只会简单的使用sybchroniezd锁。好比读者线程明显多于写者线程的状况下,就要考虑设计读者间的不互斥锁,不然的话,多个读者进程就会都被阻塞在临界区外,加剧了调度负担,也消磨了多线程并发执行所带来的优点。
一个好的事前设计会给之后的工做不管是编码仍是维护带来加速型的回报。可是事先设计也不可能考虑到全部的问题,不少问题是在编码过程当中或是实际的测试中发现的。所以在编码完成填补bug时,不能只着眼于局部的问题处理,而是要结合总体设计判断是否找到了问题的根源,及时的作好新的注释,必要的话还须要从新整合设计,避免出现拆东墙补西墙,按下葫芦浮起瓢的状况,致使原本一个较好的总体设计,最终被改得面目全非,使得往后的代码维护变得十分困难。好比如今会看多线程电梯时,大致的设计仍是看得明白的,但出现了不少细节的地方就看不明白了。这也提醒咱们,设计并非只存在编码以前,在编码时也有不断的动态设计,在编码结束后,也要回顾总体设计,针对新的问题对设计作更合理的抽象整合和重构。