301
社区成员
发帖
与我相关
我的任务
分享在 hw5 和 hw6 中,我对电梯请求队列 RequestQueue 的所有方法应用 synchronized 关键字,确保了多线程访问时的线程安全。在每次离开被锁的方法时调用 notifyAll(),唤醒所有因请求特定资源而处于等待状态的线程。
在hw7中,由于新增了双轿厢电梯的任务,我在电梯中增加了occupied 属性来标识电梯是否正在被使用。我使用了新建的 Flag 类对occupied 属性进行封装,使用封装可以隐藏实现细节,减少直接访问共享数据的机会,维护了线程的安全性。

InputHandler:处理输入,把新的电梯请求放入mainQueue,即总的请求队列。
Scheduler:电梯调度类,把电梯请求从mainQueue中取出,分配到指定的电梯对应的ElevatorQueue中
Elevator:电梯类,包含电梯运行的方法,如 move、openDoor、upload、download等。每个电梯有自己的ID、当前楼层等属性。
Passenger :乘客类,包含乘客的各种属性。
RequestQueue:存储和管理电梯请求。包含方法如 addRequest(增加请求)、removeRequest(移除请求)和 isEmpty(检查队列是否为空)等。这个队列可能被多个线程访问,因此需要同步控制。
Strategy:决策类,使用getAdvice类获得电梯运行的策略。

乘客请求调度:第一次作业中直接按要求的电梯id分配即可,不需要设计调度器。
电梯调度策略:在Strategy中实现,采用了LOOK算法,在有同向乘客时,采用捎带策略;电梯内无人,且运行方向上无请求时,电梯转向。
本次作业的迭代内容较少,增加了RESET指令和调度器。

改动较第一次作业不大,主要是完善了Schedule的部分,增加了几个电梯的属性
RESET:我把RESET指令看作是特殊的乘客,当RESET指令分配到电梯时,电梯的重置状态(resetting)置1,并且开始reset。reset时,电梯内乘客清空,且都加入此电梯的等待队列中,当电梯reset完成后,重新receive等待队列中的所有请求。没有对这些乘客重新分配加入到mainQueue中,避免了输入结束后该线程关闭的问题。
乘客请求调度器设计:我的分配策略设计的比较简单,在Scheduler类里,把请求分配给当前电梯等待队列中乘客最少的电梯。这样的操作效率并不高,但我觉得影子电梯的方法,开销太大了,换来的性能也没有特别高,且很容易出错,所以没有采用这个策略。此外,我在本周的研讨课上了解到了一种类似数学计算的方法,给不同的属性加权,通过指定的公式计算,可以得到最优电梯的id,性能也比较高,且实现起来相比影子电梯非常简单,我认为是一种很不错的实现方式。
本次作业进行了双轿厢电梯的迭代。

架构整体的变化不大,主要是增加了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也是非常的痛苦
第一次作业时,我出现了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,唤醒其他线程。