面向对象设计与构造_第二单元总结

杨馨悦-22182610 2024-04-20 18:25:05

目录

  • 同步块的设置和锁的选择
  • 三次作业架构设计
  • 第一次作业
  • UML类图
  • UML协作图
  • 调度器设计
  • 第二次作业
  • UML类图
  • 调度器设计
  • 第三次作业
  • UML类图
  • 双轿厢的设计
  • bug及debug方法
  • 心得体会

同步块的设置和锁的选择

hw5hw6 中,我对电梯请求队列 RequestQueue 的所有方法应用 synchronized 关键字,确保了多线程访问时的线程安全。在每次离开被锁的方法时调用 notifyAll(),唤醒所有因请求特定资源而处于等待状态的线程。

hw7中,由于新增了双轿厢电梯的任务,我在电梯中增加了occupied 属性来标识电梯是否正在被使用。我使用了新建的 Flag 类对occupied 属性进行封装,使用封装可以隐藏实现细节,减少直接访问共享数据的机会,维护了线程的安全性。

三次作业架构设计

第一次作业

UML类图

img

InputHandler:处理输入,把新的电梯请求放入mainQueue,即总的请求队列。

Scheduler:电梯调度类,把电梯请求从mainQueue中取出,分配到指定的电梯对应的ElevatorQueue

Elevator:电梯类,包含电梯运行的方法,如 moveopenDooruploaddownload等。每个电梯有自己的ID、当前楼层等属性。

Passenger :乘客类,包含乘客的各种属性。

RequestQueue:存储和管理电梯请求。包含方法如 addRequest(增加请求)、removeRequest(移除请求)和 isEmpty(检查队列是否为空)等。这个队列可能被多个线程访问,因此需要同步控制。

Strategy:决策类,使用getAdvice类获得电梯运行的策略。

UML协作图

img

调度器设计

乘客请求调度:第一次作业中直接按要求的电梯id分配即可,不需要设计调度器。

电梯调度策略:在Strategy中实现,采用了LOOK算法,在有同向乘客时,采用捎带策略;电梯内无人,且运行方向上无请求时,电梯转向。

第二次作业

本次作业的迭代内容较少,增加了RESET指令和调度器。

UML类图

img

改动较第一次作业不大,主要是完善了Schedule的部分,增加了几个电梯的属性

调度器设计

RESET:我把RESET指令看作是特殊的乘客,当RESET指令分配到电梯时,电梯的重置状态(resetting)置1,并且开始reset。reset时,电梯内乘客清空,且都加入此电梯的等待队列中,当电梯reset完成后,重新receive等待队列中的所有请求。没有对这些乘客重新分配加入到mainQueue中,避免了输入结束后该线程关闭的问题。

乘客请求调度器设计:我的分配策略设计的比较简单,在Scheduler类里,把请求分配给当前电梯等待队列中乘客最少的电梯。这样的操作效率并不高,但我觉得影子电梯的方法,开销太大了,换来的性能也没有特别高,且很容易出错,所以没有采用这个策略。此外,我在本周的研讨课上了解到了一种类似数学计算的方法,给不同的属性加权,通过指定的公式计算,可以得到最优电梯的id,性能也比较高,且实现起来相比影子电梯非常简单,我认为是一种很不错的实现方式。

第三次作业

本次作业进行了双轿厢电梯的迭代。

UML类图

img

架构整体的变化不大,主要是增加了Flag类,和电梯的一些属性。

双轿厢的设计

我参考讨论区同学的做法,在电梯中增加了occupied 属性来标识电梯是否正在被使用。我使用了新建的 Flag 类对occupied 属性进行封装,并且给Flag类的方法都上了锁,确保了线程安全。当电梯来到transFloor后,先检查是否occupied,被occupied的话就wait,没有的话就setOccupied,并arrive transFloor。同时要注意,给AB电梯的occupied属性设置共享对象。

public class Flag {
    
    private boolean occupied;
    
    public Flag() {
        this.occupied = false;
    }
    
    public synchronized void setOccupied() {...}

    public synchronized void setRelease() {...}

    private synchronized void waitRelease() {...}
}

当电梯到达transFloor,完成各种任务后,会立即离开transFloor,从而保证两部电梯不会相撞。

bug及debug方法

本次作业出现了好多bug,debug也是非常的痛苦

第一次作业时,我出现了RTLE的bug。我在Schedule中,分配乘客时,如果读到的乘客==null,应该continue,但我笔误写成了return,导致退出了run方法,但线程没有结束。

第一次作业的debug,我用了讨论区中睿睿学长写的testmain,比print要方便~

第二次作业,我出现了两个bug。其中一个是我在reset的时候,如果乘客已经到达了目的楼层,我忘了给乘客删除,又加入了电梯的请求队列中,这导致电梯不会接人,但线程也不会停止。第二个bug是,我的电梯在reset时不会receive乘客,就会出现当5个电梯都在reset时,只有一个电梯在receive乘客,接收大量的请求,导致tle,且效率较低。解决方法就是在reset时也receive,reset结束后再一起输出。

第三次作业,我一开始没有给AB电梯设置共享对象,导致虽然写了occupied,但电梯仍然会相撞。解决方法是,在mainClass里建立每两个电梯的共享flag。

后两次作业的debug都是通过print大法实现的。我主要打印的东西有:线程setEnd或close时打印;电梯getAdvice返回的结果;再根据问题锁定具体是哪部分写的有问题,再去打印详细的内容。

此外,还可以通过 Jconsole 插件进行检查。

心得体会

本次作业在层次化设计这部分做的比较好,这对于后续的迭代有很大的帮助。

线程安全部分,我在这个单元的作业中,出现了多次线程安全的问题,经常有电梯线程不结束的问题,这其中有些是自己的代码逻辑出现了问题,导致电梯线程一直在wait或者接受其他指令,没有进行close。还需要注意,AB电梯需要共享对象,锁在设计的时候,不能锁的太多,导致性能下降。不要忘了notifyAll,唤醒其他线程。

...全文
53 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧