我知道这个站点已经讨论过类似的问题,但考虑到一个具体的例子,我还没有得到他们的帮助。我可以从理论上掌握 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
总是碰巧唤醒同一个线程,并且不满足条件的那个线程。
尽管与您的问题没有直接关系,但我觉得引用这个结论也很重要(原作者强调):