一、同步块的设置和锁的选择

第五次作业

​ 本次作业只设置了两个线程,Input 类和 Elevator 类,这两个线程类共享同一个资源 FloorWaitTable 类。Input 类中有一个同步块,将FloorWaitTable 对象锁住,并将新读取的乘客请求存放到该共享对象中;Elevator 类中有多个同步块:线程每个循坏开始时,将共享对象锁住,根据对象判断是否结束线程和是否需要等待,之后在获取下一次目标楼层和进乘客的时候分别设置同步块。

第六次作业

​ 本次作业在第一次作业的基础上,将单电梯改成可动态增加的多电梯,在 Input 中可以启动新的电梯线程。在同步块的设置和锁的选择上,本次电梯在第一次作业的基础上,减少了程序中同步块的数量,进一步降低了线程安全问题的可能。Input 类中同样也只有一个同步块,与第一次作业相同。Elevator 类中增加了一个 myFloorWaitTable 属性,用于保存本电梯需要接送的乘客请求,Elevator 类中只有一个同步块,在该同步块中,将共享对象 FloorWaitTable 类中的乘客请求一次性全部 dump 到该电梯的 myFloorWaitTable 中,电梯之后的运行就与共享对象无关,从而减少了对同步块的使用。

第七次作业

​ 本次作业增加了电梯属性,所以考虑了换乘策略,因此每个电梯都可能向 FlorrWaitTable 中重新投放请求,所以本次作业中 Elevator 类中设置了多个同步块,分别用于判断线程是否结束,并将需要换乘的乘客请求重新投放到 FloorWaitTable 中。

二、调度器设计

​ 三次作业中我几乎都用的是ALS调度策略,并没有单独设置调度器类,而是将调度策略放在 Elevator 类中,电梯策略的实现其实是在电梯判断下次移动方向时进行的。电梯的运行过程可以抽象成一个周期:判断下一次移动方向、移动一层、判断是否需要开门并执行开门操作。在电梯判断下一次移动方向时,根据楼层中的乘客请求使用ALS调度策略进行调度。因此在调度器与线程的交互方面,我实际上是将调度器放在了电梯线程中,在电梯线程执行的过程中调度器即可发挥作用,实现交互。

三、架构设计的可扩展性

第五次作业

UML类图

imageimageimageimage

第六次作业

UML类图

imageimageimageimage

第七次作业

UML类图

imageimageimageimage

UML顺序图

image

扩展性分析

​ 本单元作业的扩展性主要表现在对电梯属性的改变,以及在程序运行时增加额外的电梯,我的作业中并没有将所有电梯的公共属性提炼整合成一个电梯接口,供各个不同类型的电梯实现,因此可扩展性和封装性比较差。在增加额外电梯时,直接在 Input 线程中启动新的电梯线程即可实现,因此可扩展性较好。

四、程序bug

​ 三次作业中只有第一次作业存在一个bug,这个bug是在我判断接送楼层的时候将最高楼层误写成了19层而导致。

五、找出bug所用的策略

​ 本单元找bug时主要考虑的是线程安全问题可能引发的bug,因此找bug时重点关注了代码中有关线程运行的部分,比如是否会产生轮询,是否会出现死锁等情况。

六、心得体会

​ 多线程编程是一个比较抽象的编程模式。本单元作业是我第一次接触多线程编程,对很多概念如锁、同步块、等待池、死锁、notifyAll都不了解,不过在不断地动手实践、犯错误又修改错误的过程中,我对这些概念逐渐有了清晰的理解,并通过三次作业的迭代,逐渐掌握了多线程编程的一些技巧。通过本单元的学习,我不仅学习了多线程编程的入门知识,更在不断地试错和纠正中锻炼了自己的编程能力,调试技巧和整体构思能力。

posted on 2021-04-25 18:45  李润洋  阅读(61)  评论(1编辑  收藏  举报