这是我写的多线程队列的小片段,

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/

10-12 00:32