面向对象程序设计第二单元作业总结
一、线程的互斥处理
在多线程的学习中,我们会发现,多线程程序中的各个线程都是自由运行的,所以如果不加入线程的互斥处理,有的时候可能多个线程同时操作同一个实例。这样就会引发问题,这样的问题最早出现在我的作业二中,具体的现象是,有一个乘客同时上了两个不同的电梯,被“一分为二”。
为了解决这样的问题,我使用的方法就是给线程加锁,锁是用来保证线程安全的,对于共享对象,我们需要在其被使用时对其加锁,保证同一时间仅能对同一共享对象进行操作。
其中,需要加锁的部分在于我们对乘客信息的添加与读取,在我们读入一个新需求并把其加到等待序列的时候,以及从等待序列中取出需求,加入到电梯的线程中时,都需要加锁。在声明方法时,在前面加上关键字
synchronized,那么就能够让我们的方法在某一时刻只能由一个线程运行。例如,我的代码中,实现从等待队列中取出一个需求的方法如下:
public synchronized MyRequest getOneRequest() {
if (myRequests.isEmpty() && (!isEnd | count != 0)) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (myRequests.isEmpty()) {
return null;
}
MyRequest myRequest = myRequests.get(0);
myRequests.remove(0);
notifyAll();
return myRequest;
}
在我们的作业中,因为所有的取出,加入操作都与“等待队列”这样一个抽象类有关系,于是在我的代码中,也仅对于此类进行了加锁。
二,线程的协作
除了对于线程访问同一个数据的限制之外,我们也应该对线程的状况进行更加精确的控制,比如当我的等待队列中没有某一个电梯所需要的需求,那么我应该让这个电梯线程进入等待状态,而不是重复查询需求——也就是我们常说的轮询。
此外,电梯处于等待状态不会自动返回,当我们有新的需求加入到队列中,我们应该重新激活电梯,让电梯获取到可加入的需求。当所有的需求都已经满足,并且输入已经结束,我们应该让线程也随之结束。
要满足如上的几个问题,就要用到控制线程的wait , motifyall 等方法。
public synchronized MyRequest getOneRequest() {
if (myRequests.isEmpty() && (!isEnd | count != 0)) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (myRequests.isEmpty()) {
return null;
}
MyRequest myRequest = myRequests.get(0);
myRequests.remove(0);
notifyAll();
return myRequest;
}
还是同样的获取需求的方法,在这里我们则主要关注其中的 try - catch 方法,这个方法的主要
作用在于:当我们获取一个新的需求,而我们的队列中没有可加入的需求时,让此请求队列等待。
public synchronized void addRequest(MyRequest myRequest,boolean isFirst) {
myRequests.add(myRequest);
if (isFirst) {
count++;
}
notifyAll();
}
与之对应的就是加入一个需求的方法,在我们新加入一个需求的时候,使用notifyall方法唤醒等待的线程,这样就实现了在没有需求的时候等待,获得新的需求的时候唤醒,重新处理需求。
那是如何判断已经结束的呢?我采用了一种计数的方法,对于每一个需求,如果是第一次加入到等待队列中,那么让count++,在完成此需求后,令count--。每次判断的时候,需要检查我的count是否等于0。此外,当输入线程结束输入的时候,会设置等待序列的isEnd属性,当count为0并且isEnd设置为真,那么我的等待序列已经结束,需要设置其它电梯内部的等待序列的isEnd属性,那么这个问题就递归到了每个电梯内部的等待序列的结束处理。之后,只需要和之前一样处理就可以——需要满足所有的电梯等待序列均为空。
三,线程的协同框架
第一次作业
第二次作业
第三次作业
四,Bug修复
第一次作业中,设置错误电梯人数,错误设置为7,导致强测挂掉,修复后无问题。
第二三次作业中,在强测时没有出现问题,但是互测暴露了问题:电梯的调度策略考虑不全面,导致有部分乘客需要纵向电梯换乘,但是无法分配正确的电梯,此外出现的RTLE错误在于线程之间的协作考虑不全面。
五,hack情况
第一次作业,由于是c房,提交的简单数据也能hack到不少的人。此后提交的数据主要卡了其它同学的线程和调度问题,只发现了一个同学有调度上的bug。
六,心得体会