notify 和 notifyall 显示奇怪的行为以等待多个线程

notify and notifyall showing weird behavior to wait of multiple threads

我以为我完全理解 notifyAll() 和 notify() 之间的区别,但后来我突然遇到这段代码,我无法弄清楚它的输出。所以我需要一些帮助来理解奇怪的输出...

注意:- 在注释 //3 和取消注释 //4 之后输出为:-

Waiting for Calculations...
Waiting for Calculations...
Waiting for Calculations...
Total is : 4950

(这似乎是合理的,好像 Thread() 在 3 个等待线程之后启动并且因为它调用 notifyAll() 并且等待线程中的一个将获得锁并执行所以显示总数,而其他线程仍在等待)

在注释 //4 和取消注释 //3 之后输出为:-

Waiting for Calculations...
Waiting for Calculations...
Waiting for Calculations...
Total is : 4950
Total is : 4950

(我认为这很奇怪,当 Thread() 在两个等待线程之后启动时,第一个输出将获得锁定,只有一个应该显示总数。但是为什么第二个总数显示为输出。)

Code :-

class Reader extends Thread {
    Calculator c;

    public Reader(Calculator cal) {
        c = cal;
    }

    public void run() {
        synchronized (c) {
            try {
                System.out.println("Waiting for calculations...");
                c.wait();
            }
            catch (InterruptedException e) {
            }

            System.out.println("Total is : " + c.total);
        }
    }

    public static void main(String arsg[]) {
        Calculator calculator = new Calculator();

        //Thread at 3rd and 4th position

        new Reader(calculator).start();
        new Reader(calculator).start();
        new Thread(calculator).start();  //3
        new Reader(calculator).start();
        //new Thread(calculator).start();    //4
    }
}

//----------------------------------------------------------------


class Calculator implements Runnable {

    int total;

    public void run() {
        synchronized (this) {
            for (int i = 0; i < 100; i++) {
                total += i;
            }

            notifyAll();
        }
    }
}

Code is modified and taken from kathy sierra Is it the case of spontaneous Wakeup (other wake up is by jvm)

这是一个简单的竞争条件。在一种情况下,notifyAll 发生在只有一个线程调用了 wait 之后。在另一种情况下,notifyAll 发生在两个线程调用 wait 之后。在不同的条件下,none 或所有其他线程 could/would 调用了 wait

notifyAll 不能追溯。它只会唤醒那些已经 waiting 的线程,而不是那些稍后调用 wait 的线程。

我已经得到了答案,但我仍然想 post 我最终修改的代码解决了我对这个问题的所有疑虑....

http://paste.ubuntu.com/11881225/

Code:-

class Reader extends Thread
{
    Calculator c;

public Reader(Calculator cal)
{
    c=cal;

}

public void run()
{
    synchronized(c)
    {
        try{
            System.out.println("Waiting for calculations...");
            c.wait();
        }
        catch(InterruptedException e){System.out.println("Exception occured");}

        System.out.println("Total is : "+c.total);
    }
}   

public static void main(String arsg[])
{
    Calculator calculator=new Calculator();

    new Reader(calculator).start();     
    new Reader(calculator).start();     
    new Reader(calculator).start();     

    new Thread(calculator).start(); // Change position of this line while experimenting


}
    }
    //----------------------------------------------------------------
    class Calculator implements Runnable

{
    int total;

public void run()
{
    synchronized(this)
    {
        for(int i=0;i<100;i++)
        {
            total+=i;
        }
        System.out.println("Before Notify");
        notifyAll();
        System.out.println("After Notify");
    }
}
}