301
社区成员
发帖
与我相关
我的任务
分享1. 主要锁的选择:
public synchronized void addRequest(MyRequest request) {
requests.add(request);
notifyAll();
}
public synchronized void addRequest(MyRequest myRequest) {
int fromFloor = myRequest.getFromFloor();
getSubRequests(fromFloor).add(myRequest);
notifyAll();
}
2. 同步块的设置:
3. 锁与同步块中处理语句之间的关系:
结合线程协同的架构模式(如流水线架构),分析和总结自己
三次作业架构设计的逐步变化和未来扩展能力画UML类图



三次作业逐次迭代,其中必要重要的变化有以下几条
第一次到第二次的作业中,增加了Scheduler类。第一次作业中,由于输入会直接指定乘客需要乘坐的电梯,因此没有必要设置专门的调度类来把乘客分配给电梯。第二次作业中,不再指定需要乘坐的电梯,而是自定策略来把请求分配给电梯,以达到更好的性能;同时由于调度类的增加,也相应的需要增加一个ProcessQueue类,并且设置单例模式,作为请求未分配前的总请求队列。
第二次到第三次的作业中,增加了Controller类,因为前两次的作业中,电梯的运行逻辑直接在电梯中实现,包括了重置,开关门,进出乘客,运行。
@Override
public void run() {
while (true) {
if (currentPeople.isEmpty() && requestQueue.isEmpty() && !reset) {
if (processQueue.isRealEnd()) {
return;
} else {
elevatorWait(); } }
if (reset) {
if (!currentPeople.isEmpty() && resetDepth != 0) {
resetDepth--;
} else if (currentPeople.isEmpty()) {
reset();
} else if (resetDepth == 0) {
display(Motion.OPEN);
goToSleep(openTimeConsuming + closeTimeConsuming);
currentPeople.release(currentFloor,elevatorId,true,processQueue);
display(Motion.CLOSE);
reset();
}
}
boolean mark1 = currentPeople.isSomeoneWantToOut(currentFloor);
boolean mark2 = requestQueue.isSomeoneWantToIn(currentFloor, direction)
& (residualCapacity() != 0);
boolean mark3 = currentPeople.isEmpty()
& !requestQueue.isSomeoneWaitingAhead(currentFloor, direction)
& requestQueue.isSomeoneWantToTurn(currentFloor, direction);
if (mark1 || mark2 || mark3) {
display(Motion.OPEN);
goToSleep(openTimeConsuming + closeTimeConsuming);
if (mark1) {
display(Motion.OUT);
}
if (requestQueue.isSomeoneWantToIn(currentFloor, direction)
& (residualCapacity() != 0)) {
display(Motion.IN);
}
if (currentPeople.isEmpty()
& !requestQueue.isSomeoneWaitingAhead(currentFloor, direction)
& requestQueue.isSomeoneWantToTurn(currentFloor, direction)) {
elevatorTurn();
display(Motion.IN);
}
display(Motion.CLOSE);
}
boolean flag1 = !currentPeople.isEmpty();
boolean flag2 = currentPeople.isEmpty()
& requestQueue.isSomeoneWaitingAhead(currentFloor, direction);
boolean flag3 = currentPeople.isEmpty()
& requestQueue.isSomeoneWaitingBehind(currentFloor, direction);
boolean flag4 = currentPeople.isEmpty()
& requestQueue.isEmpty() & (!processQueue.isRealEnd()) & (!reset);
if (flag1 || flag2) {
elevatorMove();
} else if (flag3) {
elevatorTurn();
} else if (flag4) {
elevatorWait();
}
}
}
这样会导致出现很多意想不到的bug,电梯的运行逻辑没有得到适当的划分。因此在第三次作业中,增加了Controller类,对电梯的运行逻辑进行切分和控制。在这样的修改之后,Elevator的运行逻辑为:
@Override
public void run() {
while (true) {
switch (controller.getInstruction()) {
case OPNE_AND_CLOSE:
openAndClose();
break;
case MOVE:
move();
break;
case TURN:
turn();
break;
case WAIT:
if (requestQueue.size() != 0) {
break;
}
myWait();
break;
case RESET:
reset();
break;
case SUB_RESET:
subReset();
return;
case FINISH:
return;
default:
}
}
}
Controller一共可以做出7中行为决策,这些行为决策作为枚举类封装在了Instruction中:
public enum Instruction {
OPNE_AND_CLOSE,
SPE_MOVE,
MOVE,
TURN,
WAIT,
RESET,
SUB_RESET,
FINISH
}
画UML协作图(sequence diagram)来展示线程之间的协作关系

识别出三次作业稳定的内容和易变的内容,并加以分析
稳定的内容:
if (requestQueue.hasNormalReset()) { return Instruction.RESET; }
else if (requestQueue.hasDoubleCarReset()) { return Instruction.SUB_RESET; }
else if (currentPeople.isSomeoneWantToOut(currentFloor)
|| (requestQueue.isSomeoneWantToIn(currentFloor, direction)
& (elevator.getResidualCapacity() != 0))
|| (currentPeople.isEmpty()
& !requestQueue.isSomeoneWaitingAhead(currentFloor, direction)
& requestQueue.isSomeoneWantToTurn(currentFloor, direction))) {
return Instruction.OPNE_AND_CLOSE;
}
else if (!currentPeople.isEmpty()
|| (currentPeople.isEmpty()
& requestQueue.isSomeoneWaitingAhead(currentFloor, direction))) {
return Instruction.MOVE;
}
else if (currentPeople.isEmpty()
& requestQueue.isSomeoneWaitingBehind(currentFloor, direction)) {
return Instruction.TURN;
}
else if (processQueue.isFinished()) {
return Instruction.FINISH;
}
else {
return Instruction.WAIT;
}
易变的内容:
InputHandler输入处理器
第二次作业新增了重置请求,第三次作业新增了双轿厢重置请求。因此都需要调整输入处理器。
ELevator的run方法
由于电梯的运行逻辑越来越复杂,在第二次作业中新增的重置请求使得电梯在运行前要先判断是否需要重置,并进行一些列操作:
private void reset() {
// 1. 清除现有人员
if (!currentPeople.isEmpty()) {
TimableOutput.println("OPEN-" + currentFloor + "-" + id);
goToSleep(openTimeConsuming + closeTimeConsuming);
currentPeople.release(currentFloor, true);
TimableOutput.println("CLOSE-" + currentFloor + "-" + id);
}
// 2. 开始重置
// 1. 打印开始
TimableOutput.println("RESET_BEGIN-" + id);
goToSleep(100);
requestQueue.releaseVers();
// 2. 睡觉
goToSleep(1100);
// 4. 打印结束
TimableOutput.println("RESET_END-" + id);
// 3. 更新数据
capacity = requestQueue.getResetCapacity();
moveSpeed = requestQueue.getResetSpeed();
ProcessQueue.shared().subCounterForReset();
requestQueue.removeReset();
}
在第三次作业中需要判断重置的类型,对于双轿厢电梯进行不同的逻辑操作:
private void subReset() {
// 1. 重置
if (!currentPeople.isEmpty()) {
TimableOutput.println("OPEN-" + currentFloor + "-" + id);
goToSleep(openTimeConsuming + closeTimeConsuming);
currentPeople.release(currentFloor, true);
TimableOutput.println("CLOSE-" + currentFloor + "-" + id);
}
TimableOutput.println("RESET_BEGIN-" + id);
goToSleep(100);
requestQueue.releaseVers();
goToSleep(1100);
TimableOutput.println("RESET_END-" + id);
// 2. 在调度器中删除此电梯,及其队列
Scheduler.shared(null,null).removeEntry(this);
// 3. 新建电梯: 锁共享,队列提前创建; 先启动电梯,再加入调度器
RequestQueue requestQueueA = new RequestQueue(id,'A');
RequestQueue requestQueueB = new RequestQueue(id,'B');
SpecialMove specialMove = new SpecialMove();
int resetCapacity = requestQueue.getResetCapacity();
int resetMoveSpeed = requestQueue.getResetSpeed();
int resetTransFloor = requestQueue.getResetTransFloor();
SubElevator subElevatorA = new SubElevator(id,'A',specialMove,
resetCapacity,resetMoveSpeed,resetTransFloor,requestQueueA);
subElevatorA.setName("Elevator " + id + "-A");
SubElevator subElevatorB = new SubElevator(id,'B',specialMove,
resetCapacity,resetMoveSpeed,resetTransFloor,requestQueueB);
subElevatorB.setName("Elevator " + id + "-B");
ProcessQueue.shared().subCounterForReset();
requestQueue.removeReset();
subElevatorA.start();
subElevatorB.start();
Scheduler.shared(null,null).addEntry(requestQueueA,subElevatorA);
Scheduler.shared(null,null).addEntry(requestQueueB,subElevatorB);
}
对SpecialMove方法上锁
设置了一个SpecialMove类,该类只含有一个move方法。该move方法包含了一系列的运行流程。
包括了:
具体来说:
SpecialMove specialMove = new SpecialMove();
SubElevator subElevatorA = new SubElevator(...,specialMove,...);
SubElevator subElevatorB = new SubElevator(...,specialMove,...);
public synchronized void move(SubElevator elevator) {
elevator.move();
elevator.openAndClose();
if (elevator.myGetType() == 'A') {
if (elevator.getDirection() == Direction.UP) {
elevator.turn();
}
elevator.move();
notifyAll();
return;
} else {
if (elevator.getDirection() == Direction.DOWN) {
elevator.turn();
}
elevator.move();
notifyAll();
}
}
这样就可以保证在即将移动到换乘楼层时,只有一部电梯占用SpecialMove进行运行,另一部电梯如果此时也要进入换乘楼层则必须等待,直到另一部电梯释放SpecialMove的锁