OO第二单元总结
同步块的设置和锁的选择
第一次
在第一次作业中,在我采用的设计中,共享对象只有RequestQueue
一个类,所以在用到其时,直接使用synchronized
锁以确保线程的安全。而对于同步块的设置,在第一次作业中,由于仿照实验的写法,在RequestQueue
的方法上加上了synchronized
,所以绝大多数直接使用了方法,而没对对象设置。
第二次
第二次作业相较于第一次作业,只增加了横向的电梯,而逻辑上的区别不大,因此同步块的设置和锁的选择和第一次一致
第三次
第三次作业,相较于前两次的作业,由于横向的电梯存在着可达性的判断,在选择具体的电梯时也需要楼层,速度等信息,所以我在Mainclass
和Schdule
这两个类之间利用多个HashMap
来传递信息,而HashMap
本身是线程不安全的,所以我用了一个类Eleinfo
来放置多个HashMap
,并而访问其中的信息时,均通过这个Eleinfo
类来进行,而访问时的Synchronized
锁就加在这个类上。
调度器设计
第一次
在第一次作业中,由于只有五台电梯,我的调度器直接从waitQueue
中取出Request
后,根据所在的楼座直接放入对应电梯的requestQueue
即可。
第二次
在第二次的作业中,加入了横向的电梯以及一个楼座中多台电梯的情况。则在第一次的基础上加入了对PersonRequest
横向和纵向的判断,以及通过比较同一楼座中每一个电梯中已经有的人数,选择加入到人数较少的电梯的requestQueue
的队列中去即可。
第三次
在第三次的作业中,由于加入了中转,我将所有的PersonRequest
分为了三步,并在调度器中对于步骤执行完的,认定为完成,第一、三步未执行的,认定为加入纵向电梯队列中,第二步未执行完的,认定为加入横向队列中。
同时,在第二次的基础上,将同一楼座、层数的电梯的选择,由根据人数改为根据人数和速度。
总体而言,调度器与其他线程的交互,主要是通过共享对象,在本作业中,即各个请求队列。
框架模式
架构设计和未来扩展能力
第一次作业的整体架构较为简单,在MainClass
里创建Elevator
的线程,接受读入的信息,在这里,我并没有建立Input
这样一个类来处理输入的信息,直到第三次也没有,发现,尽管这样做是可行的,但是会导致MainClass
中存在大量的代码,耦合性强,在我第二次、、第三次修改的时候,并不方便。在Mainclass
接受到输入的Request
后,放入到一个作为共享对象的队列中去,传给Schdule
。即采用了生产者消费者的模式。在Schdule
这个类中将Request
分配给各个电梯。由电梯自己负责自己的运行。
而电梯的具体策略,做为一个类放在电梯中,这样可以在更改电梯的具体运行策略时较为方便
而在第二次作业中,加入了横向电梯Crosselevator
这样一个类以及对应的策略,尽管在第一次中考虑到了电梯可能有不同的策略这件事,但是横向电梯的具体运行由于存在着环形的问题,和纵向电梯的运行差距较大,不是仅仅更改运行策略就可以实现的,所以重新写了横向电梯类。而其他的方面与第一次作业的架构类似。均是由Schdule
分配请求给电梯。
在第三次的作业中,发现由于创建电梯所需的代码量较大,将创建电梯这一步骤放在原本的位置,使得代码量变大,难以发现问题,因此建立了一个类用于创建电梯。同时由于将一个PersonRequest
分为三步执行,但是如果直接利用提供的类,无法记录执行到了哪一步,因此建立了Person
类,在其中保存已经执行了的步骤。同时,建立了Eleinfo
类,作为MainClass
和Schdule
之间的共享对象传递信息。
同时,由于并不是人坐一次电梯就结束了,因而仿照实验写法,建立了RequestCounter
类用于判断是否结束。
对于未来继续的可能的扩展,认为没有建立Input
的类处理输入,是不利于扩展的。同时,强行认为每个人的路径分为三步,在未来的扩展中,也是非常不利的,对于可能的多次换乘,或者特殊的要求,均难以扩展。认为可以用一个属性,保存所需要的总的各个步骤,在Input
中得到这些步骤,是相较于当前更适合扩展的方法。而对于电梯的可达性,电梯的策略,这些方面,则是较为容易进行扩展的。
UML类图
UML协作图(sequence diagram)
bug分析
-
用
for
循环移除元素时,忘记将当前标记减1重写为用iterator
-
发现在代码量较大的地方,容易出现输入的错误
-
在判断选择横向电梯时,打错了比较的楼层,导致了添加的电梯全部没能使用,RTLE
改回正确的楼层判断
-
第三次作业选择中转楼层时,忘记让不用换乘的请求的中转楼层设置为
fromfloor
,从而出现到默认的1楼换乘的现象。加上一个判断,在不用中转时,
transfloor
等于fromfloor
-
发现别人bug的策略
通过对代码的观察,主要检查遍历是否有问题,是否存在线程不安全,手动构造一些样例。
但由于个人较为懒惰,大多数情况下看了一点就开摆了。
因为多线程的偶然性,bug难以复现,本单元的bug较难寻找。
心得体会
线程安全
在本单元的学习中,个人认为最大的收获就是对于多线程的学习,从对于多线程没有一点了解到了现在至少知道了基本的利用synchronized
对于线程的安全性进行保证,保证对共享对象的操作互斥,并利用共享对象实现线程间的交互。
同时也了解了加锁中对象的选择,同步区的选择等等问题,并不是盲目的加锁就可以保证线程的安全,反而可能影响到实际的效率
同时,也知道了自己只了解了多线程的一小部分,对于更多的锁的类型,线程安全的类等等的了解还不够
层次化设计