301
社区成员
发帖
与我相关
我的任务
分享任务简介:模拟多线程实时电梯系统,通过设计,系统可以调度多部电梯完成乘客请求或重置操作。
采用了不需自己实现的synchronized这种锁,它可以:
在实现中仅用了前一种使用方式,即“对方法加锁”,对于设置的共享对象,即候乘表类中的每一个方法都用synchronized关键字修饰,确保其被多个线程修改和访问时不会出现问题。所以,锁的对象应该是同步块代码语句中修改需要保护的对象。synchronized可以修饰静态方法,也可以修饰实例方法,但二者锁的对象却存在差别,注意需要正确选择。
调度器需要对Request进行处理,以便请求能够被正确满足,将其单独作为一个线程。
该线程需要与输入线程、电梯线程进行交互,它们之间其实是生产者-消费者这一协作关系,与输入线程这一生产者之间的“托盘”是总候乘表,而与电梯线程这一消费者之间的“托盘”则是每个电梯各有的子候乘表。特别地,由于电梯重置时会将未完成请求重新返还给调度器进行再分配,所以电梯也是生产者,它们之间的“托盘”也是总候乘表。
调度策略需要综合考虑到各方面的因素,从乘客的角度来说,我们不希望完成请求的时间过长,而从电梯的角度考虑,我们希望能多多捎带,减少非必要移动和开关门,降低耗电量。
在hw6中,由于需要自己分配完成请求的电梯,我采用了下述调度策略:
<1>
优先分配给LOOK算法下能捎带的电梯。
注意“能捎带”是指不会导致原有请求无法完成,即不会出现原定捎带由于满员而无法满足的问题。
<2>
无可捎带电梯,分配空电梯。
这主要是考虑到时间问题,通过分配空闲电梯,可以使得请求及时得到满足。
<3>
无满足上述两种情况电梯,则分配给现有请求数最少的电梯。
当然也可能出现请求数相等情况等,此时可以从是否在重置、是否为双轿厢(耗电少)、电梯所处楼层与目标楼层的距离等方面考虑最终分配给哪个电梯。
LOOK算法:
LOOK算法优势:
课程组采用ALS调度策略为性能基准,但是通过查阅资料和研讨课讨论,最终选择了LOOK作为调度算法
UML类图
hw5

现在回看第一次作业的设计,可以说有很多不合理和不成熟的地方,但是也是建立起了整个请求处理的架构,形成了输入线程和电梯线程间的协作关系。主要的缺陷有:
hw5->hw6/7

DoubleElevator等。 run()方法,则可以通过实现Runnable接口的方式,以及通过子调度器来调度双轿厢电梯我总觉得有不妥之处,或许有更好的形式来实现。协作图

上图中展现了不同线程之间的协作关系,其中InputThread、Scheduler、Elevator三者之间的协作还需要通过总候乘表waitTable来实现,Scheduler和Elevator之间的协作也需要通过子候乘表RequestTable来完成,确保线程协作的正确性。
稳定/易变的内容
LOOK策略)在第一次作业中确定后则一直沿用,可以说是十分稳定。毕竟无论电梯的形式再怎么变化,最终都是要“把分配给其的请求完成”,所以从纵向调度的角度来说,这会是比较稳定的部分,不需要做过多的修改。在hw7中,电梯可以进行双轿厢重置,即经过该类重置后的电梯井内存在两辆电梯,分别在划定的上、下两区中移动,且都可以进入换乘层,如何避免双轿厢电梯在换乘层相撞,设计上是这样实现的:
Step1 新建换乘楼层类TransferFloor,确保该类是线程安全的,可以被A/B电梯正确地修改。对于经过双轿厢重置的“电梯”(保留初始时电梯序号的概念,实际上描述为“电梯井”更加贴切),实例化一个TransferFloor对象,指示该电梯井中的换乘楼层是否被occupied,同时可以完成状态的set和release操作。
public class TransferFloor {
enum State { OCCUPIED, UNOCCUPIED }
private State state;
public TransferFloor() {
this.state = State.UNOCCUPIED;
}
public synchronized void setOccupied();
public synchronized void setRelease();
private synchronized void waitRelease();
}
Step2 对于双轿厢电梯,若经过移动操作到达换乘层,则执行setOccipied()操作,setOccupied()方法的具体实现是:
public synchronized void setOccupied() {
waitRelease(); //state为occupied则电梯wait,否则进入换乘层
state = State.OCCUPIED; //进入换乘层,将换乘层状态设为occupied
notifyAll();
}
Step3 为避免双轿厢电梯相撞,和电梯在需要时都可以顺利(或经过短时间等待后)进入换乘层,在本次设计中,不允许电梯在换乘层中驻留,即在电梯策略类中,若给出wait建议时电梯处于换乘层,则将该种情况下建议变为向远离换乘层方向移动,同时将换乘层状态变为unoccupied。这样就避免了某电梯长时间占据换乘层,另一电梯无法进入或相撞的情况。
sychronized和notifyAll()保证对共享对象的访问和修改行为是线程安全的,该方法在实现上也比较简便,实验中还提供了基于读写锁的实现方式。