301
社区成员
发帖
与我相关
我的任务
分享本单元主要采用生产者消费者模式的同步方法,共享对象为乘客的请求表RequestTable
public class RequestTable {
private ArrayList<PersonRequest> insideTable = new ArrayList<>();
private ArrayList<Request> requestTable = new ArrayList<>();
......
public synchronized void putRequest(Request request) {
requestTable.add(request);
notifyAll();
}
......
public synchronized Request getRequest(int i) {
while (isEmpty()) {
if (inputEnd && sixEmpty) {
notifyAll();
return null;
}
try {
notifyAll();
wait();
}
catch (Exception e) {
e.printStackTrace();
}
}
if (isEmpty()) {
notifyAll();
return null;
}
Request ret = requestTable.get(i);
notifyAll();
return ret;
}
......
}
可以看出,共享对象类RequestTable通过synchronized来实现同步控制,而各个线程只需要调用共享对象的同步方法即可,无需再线程内部和线程间加锁。
本单元三次作业迭代过程中,类的定义和数量均未改变,故只展示第三次作业的类图如下:

三次作业都使用了最基本的生产者-消费者模式作为作业底层逻辑,InputHandler将输入放到Schedule的列表中,Schedule负责将列表中的乘客请求分发给各部电梯。
具体到调度策略上:除了第一次作业的指派id的调度策略,后两次调度均采用顺序调度的方式进行调度,逻辑如下:
roundState();
PersonRequest personRequest = (PersonRequest)request;
while (elevatorTableList.get(curEle).getStatus() == 0) {
roundState();
}
elevatorTableList.get(curEle).putRequest(request);
TimableOutput.println("RECEIVE-" + personRequest.getPersonId() +
"-" + (curEle + 1));
//roundState()方法将电梯id依次轮换。
由于乘客请求随机出现,本策略最后效果依然不错。
第三次作业中,我将一个电梯内内置双轿厢电梯,最小化了架构的改变。
协作图关系如下:

我的架构中,三次作业均无需新增类,但随着问题愈发复杂,类内复杂度还是不可避免的升高了。
正如前文所说,第三次作业我的双轿厢电梯通过单个电梯“模拟”双轿厢电梯实现,两个轿厢不碰撞的逻辑为:
虽然这样的双轿厢电梯的效率有所降低,但在编写代码实现上非常容易实现。
第一二次作业中,我的程序未出现bug,但在第三次作业中,我对双轿厢电梯的模拟逻辑出现了bug,导致强测出现了RTLE。
分析过后,我认为这是我的设计逻辑导致的:我追求每次迭代的最小改变,但当迭代次数增加时,有一些类的设计会不可避免地变得过于复杂,导致bug的产生。
本单元多线程的学习基于生产者-消费者模式展开,每次作业迭代过程中我使用了“尽量不改变原逻辑”的最小迭代方法,这种方法有好有坏,面对多次迭代后产生的bug,我应该在未来面对类似问题时加强“迭代设计”。
最后,本单元的学习实验体验还是不错的,感谢助教和老师!