第一次作业采用SSTF策略,InputHandler和Elevator两个线程共享一个RequestList。InputHandler处理输入请求,Elevator负责运行,RequestList接受、存放和调度请求。后两次作业与第一次架构基本相同。
(2)从功能设计和性能设计的平衡方面,总结自己第三次作业架构设计的可扩展性
-
Main:创建和启动线程;
-
RequestList:接受、存放和调度请求;
-
InputHandler:此线程来实现读取控制台的请求并将数据存入Queue队列;
-
Elevator:电梯父类;
-
ElevatorAElevatorBElevatorC:不同规格的电梯;
-
TransferTable:返回换乘策略。
因为写崩了所以应该谈不上有可扩展性。。。
SOLID
-
单一职责原则 Single Responsibility Principle:
每个类基本有单一的职责,但内部还可以细化,尤其是RequestList一直负责所有调度工作。
-
Open Closed Principle开闭原则:
每次迭代都修改了Elevator类。特别是run方法,第一次作业就写的比较复杂,后面修改的时候也有些混乱。我认为之后作业要更多地在第一次就想好后面可能的迭代方向,而不是只着眼完成这次的功能。
-
Liskov Substitution Principle里氏替换原则:
电梯各个子类基本上只是传了不同参数给父类,因此与父类功能一致。
-
Interface Segregation Principle接口分离原则:
不知道咋评价,因为各个类之间交互关系比较明确,好像涉及不到两个类同时用一个方法获取感兴趣的信息。
-
Dependency Inversion Principle依赖倒置原则:
同上,在这次作业中没有太涉及到这个问题
(3)基于度量分析自己的程序结构
-
第一次作业
复杂度:处理电梯行为的几个函数复杂度较高,比如乘客进出、电梯的run、获取下一波乘客。
UML类图:
-
第二次作业
复杂度:
UML类图:
-
第三次作业
复杂度:
UML类图:
(4)分析自己程序的bug
-
第一次作业
bug:为了解决线程安全问题把synchronized的范围放得很大,结果强测性能分几乎都是0。
解决办法:把synchronized范围从elevator run的循环缩小到requestList的add emove操作。
-
第二次作业
bug:电梯获取请求时调用requestList的getInBundle,但这个函数会把所有符合条件的人都塞给电梯。如果超过电梯运载能力,无法满足的请求会丢失,导致有一些乘客没进电梯。
解决办法:一开始想让电梯把人放回队列,但是会超时。改为把电梯剩余空间传给getInBundle,让requestList可以分配给电梯合适数目的乘客。
-
第三次作业
bug:大概率是出现了死锁,但没有de出来。
(5)分析自己发现别人程序bug所采用的策略
因为太菜所以主要在分析自己的bug(逃
(6)心得体会
经过这一章还是对多线程不太理解,很多地方是凭感觉加synchronized,并不是很理解具体发生了什么。多线程部分最大的困难可能是难以debug。在讨论课之后尝试用JProfiler,但是并没有定位到第三次作业死锁在哪个环节产生,总之就是比较懵逼。。。其实第一次作业实现的时候就觉得电梯的run,getInOut,getInBundle几个环节之间逻辑关系不是很清晰,第三次作业为了实现换乘,更提高了控制逻辑的复杂度,导致bug是必然的。第二次作业互测时看到一些用dispatcher制定策略的代码,想重构但是自己实现的时候还是很懵,不清楚功能分离的边界在哪里。希望能看看大佬代码梳理下思路。