BUAA OO Unit2 Summary

OO Unit2 Summary

Part1:同步块

锁的选择

  • 在完成这单元第一次作业的时候,荣老师简明扼要地提出 synchronizedwaitnotifyAll就完事了,所以在完成第一次作业的时候我并没有采用Java中的Lock类,包括ReentrantLockd等。而这个做法也延伸至第三次作业的完成,并没有更改。

块的设置与语句关系

  • 在对共享对象加锁的时候,需要明确的,我们要进行基准的原子化操作,所以把不会修改共享对象的语句放在块的前后以缩小块的粒度,去锁住最核心的语句,当然前提是这样的语句顺序不会影响结果。所以我在作业中的写法发生了从synchronized整个method到synchronized具体对象的转变。比如我们不在块中去执行new一个对象、返回结果等的操作,因为这样的操作不影响并发过程的话,就不必锁在块中加大粒度。最极端的情况就是锁住每一条语句,很显然是最安全、最笨重的做法。

Part2:Schedule

image
image
image
上图是三次作业以来Schedule的变化
Schedule为Singleton

1.起初调度器只需要管理五幢楼的请求队列,由一个Map来表示,key为楼座,value为对应队列
2.增加横向电梯后,类似地,增加一个Map来表示横向队列,key为楼层,value为对应队列
3.请求无法在一次内完成,参考exp4-2,增加Persons,调度器根据ID来记录每一个请求,每次运输后加回调度器,直到请求完全完成。

我的调度器设计很大程度上不直接与线程交互,而是负责加人、加电梯的指令传达和计算以及人的队列的管理。也就是说,对于电梯的操作只是通过了调度器这一中间部分而已,详见Part3

Part3:架构

image
image
image

1.简单的层级关系,调度器管理队列,新增请求通过调度器到底队列,完成生产,队列中可包含多部电梯来实现消费。
2.层级的基础上增加横向分支
3.与第二个架构类似,调度器增加拆分请求的功能,电梯完成请求后需要交互反馈给调度器

值得一提的是,对于电梯与请求队列,我均拆分为横向与纵向,并且没有采用工厂模式(原先实现了但觉得麻烦),这是因为我在一开始并没有给对应楼座、对应楼层的二维坐标空间创建一个类,然后让队列去包含它,如果这样,在实现调度器拆分请求的算法的时候会容易得多,可以采用最短路径相关算法,这也算是我的架构缺陷了

对于未来扩展,荣老师谈到一个记录、跟踪每一个请求的具体信息的这么一个要求,既然我的电梯与调度器存在交互,并且调度器本身就存在记录每一个请求的Persons字段,那么就容易实现。

具体的类图
image
image
image

sequence diagram如下,以第三次作业为例
image
输入部分完成后即对Schedule设置End,直到所有请求完成调度器才对逐步对电梯设置End

Part4:BUG分析

1.第一次作业迭代过程中对请求队列做了修改,导致IllegalModificationException,这主要是因为对java语法还是没掌握。修复就是阅读java文档
2.第三作业由于多余的notifyAll产生了轮询。这个BUG还是有趣的,因为写代码时常常会参考实验上助教的代码,发现对于共享对象的代码块常常会在里头notifyAll,所以我在没弄懂原理的情况下跟着模仿,以至错误。后来才学习了等待池和锁池的概念,并意识到不是所有对共享对象的操作都要notifyAll,而是应该考虑为什么要wait,与之相应的唤醒原因。当然了,还有就是不要一味地模仿,而是要预习弄清楚原理Orz。修复的时候,首先根据轮询去分析每一个while循环,并打印相关信息,就可以发现是哪个循环出了问题,然后对该循环的wait进行分析,找出wait被频繁唤醒的原因,就得知过度的notifyAll导致了问题。

Part5:hack

1.首先就是生成数据大量地短时并发,比如在同一个时间戳内产生大量请求,狂轰滥炸,有效性看运气(笑)
2.发现线程问题的策略,就是明晰共享对象,并考察锁的范围,但因为本单元共享对象明确,死锁不太容易发生,所以尤其关注轮询,特别是循环的边界条件。
3.第一单元的测试,很大程度上可以借助现有的词法分析程序,也就是降维打击,这单元测试程序均靠自己设计,主要从状态的转变入手,对象是请求的人与电梯,可以从输出信息中分类,对应电梯线程,写一个检查电梯、检查人的线程。

Part6:心得体会

  • 对于线程安全而言,我觉得第一点是克服恐惧,其实多线程也只是一个线程,不过在自己需要对于这个线程发生的事掌握得一清二楚,哪些操作会影响共享对象,哪些操作可以放任最大化速度,这是需要明确的。另一个就是莫名其妙的Debug感受,包括莫名其妙的bug生成,莫名其妙的bug消失(伪)。总的来说,私有的东西就该自己藏着,包括原子化,也是一种私有,私有着某一个对象。我推测原子化概念来源于早期物理理念,原子不可再分。原子化不是最小的操作,但是一定是最需要连贯的操作。在号召竞争的同时,多线程就是这样,要求你文明地野蛮着,抢是一方面,没抢到便是不再计较,让人完整地去干便是了。
  • 层次化角度而言,这单元层次明确,我的层次更像是递进式的,不会像第一单元让人头大,这也意味着守护的对象也是明确的,试想如果彼此之间耦合在一起,连共享的对象都你我不分,多线程又要从何入手呢?我相信,层次化的意义会帮助线程之间思路理清,谈不上层次化,就谈不上高速、安全的多线程
posted @ 2022-04-28 17:09  阿莫誒  阅读(26)  评论(1编辑  收藏  举报