我知道这个站点已经讨论过类似的问题,但考虑到一个具体的例子,我还没有得到他们的帮助。我可以从理论上掌握 notify() 和 notifyAll() 关于 Thread “唤醒”的区别,但是当使用它们中的任何一个而不是另一个时,我无法理解它们如何影响程序的功能。因此我设置了以下代码,我想知道使用它们中的每一个都有什么影响。我可以从一开始就说它们给出了相同的输出(Sum 打印了 3 次)。

它们实际上有何不同?有人如何修改程序,以便应用notify 或notifyAll 对其功能发挥关键作用(给出不同的结果)?

任务:

class MyWidget implements Runnable {
private List<Integer> list;
private int sum;

public MyWidget(List<Integer> l) {
    list = l;
}

public synchronized int getSum() {
    return sum;
}

@Override
public void run() {
    synchronized (this) {
        int total = 0;
        for (Integer i : list)
            total += i;

        sum = total;

        notifyAll();
    }
}

}

线:
public class MyClient extends Thread {
MyWidget mw;

public MyClient(MyWidget wid) {
    mw = wid;
}

public void run() {
    synchronized (mw) {
        while (mw.getSum() == 0) {
            try {
                mw.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Sum calculated from Thread "
                + Thread.currentThread().getId() + " : " + mw.getSum());
    }
}

public static void main(String[] args) {
    Integer[] array = { 4, 6, 3, 8, 6 };
    List<Integer> integers = Arrays.asList(array);

    MyWidget wid = new MyWidget(integers);

    Thread widThread = new Thread(wid);
    Thread t1 = new MyClient(wid);
    Thread t2 = new MyClient(wid);
    Thread t3 = new MyClient(wid);

    widThread.start();
    t1.start();
    t2.start();
    t3.start();
}

}

更新:
我写得很明确。无论使用notify还是notifyAll,结果都是一样的:
从线程 12 计算的总和:27
从线程 11 计算的总和:27
从线程 10 计算的总和:27

因此我的问题是:有什么区别?

最佳答案

这种差异比您的示例旨在激发的更微妙。用 Josh Bloch 的话说(Effective Java 2nd Ed,Item 69):



所以这个想法是你必须考虑在你正在等待的同一个监视器上输入 wait 的其他代码片段,以及那些吞下通知而不以设计的方式使用react的其他线程。

其他陷阱也适用,这可能导致线程饥饿,例如多个线程可能等待不同的条件,但 notify 总是碰巧唤醒同一个线程,并且不满足条件的那个线程。

尽管与您的问题没有直接关系,但我觉得引用这个结论也很重要(原作者强调):

10-07 23:34