这是我写的多线程队列的小片段,
synchronized void add(int i) {
if (count == size) {
System.out.println("******full***");
isQueueFull = true;
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("adding number: " + i);
val[end++] = i;
count++;
if (isQueueEmpty) {
isQueueEmpty = false;
this.notifyAll();
}
}
synchronized int remove() {
if (count == 0) {
isQueueEmpty = true;
System.out.println("******empty***");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int t = val[0];
for (int i = 0; i < end - 1; i++) {
val[i] = val[i + 1];
}
val[end - 1] = -1;
end--;
count--;
if (isQueueFull) {
isQueueFull = false;
this.notifyAll();
}
System.out.println("removing number: " + t);
return t;
}
可以说我有四个线程添加到队列中,一个线程从队列中删除。一方面,说阵列已满,然后我在添加到队列的所有四个线程上调用wait。
现在,当元素被删除时,我需要在所有睡眠线程上调用notifyAll。(这给我一个arrayOutofBound异常)我的问题是,在notifyAll情况下,线程的流向是怎样的?
由于add是同步方法,因此只能执行一个线程。但是由于等待,我们现在其中有四个线程正在睡眠。因此,在notifyAll上,所有四个线程是否仍将位于add方法内(尽管它是同步方法)并执行?还是按顺序依次完成,所有线程都被锁定,直到一个线程完成。
我很难在Eclipse中调试它。我可以通过在等待后放置return语句来解决arrayOutOfBoundException的问题,但是在notifyAll的情况下,我仍然想了解流程?
最佳答案
等待与睡觉大不相同。 javadoc of wait()
对此进行了解释:
线程释放此监视器的所有权,并等待直到另一个线程通过调用notify方法或notifyAll方法通知等待在此对象监视器上等待的线程唤醒。然后线程等待,直到它可以重新获得监视器的所有权并恢复执行。
(强调我的)
顺便说一句,它还包含一个不遵守的强大规则:
与一个参数版本一样,可能会发生中断和虚假唤醒,并且此方法应始终在循环中使用:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
因此,当调用
notifyAll()
时,这4个线程竞争以取回监视器。一旦上一个已释放它,每个都将其取回,并继续执行。关于java - notifyAll在这种情况下将如何工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25472553/