转载:用实例揭示notify()和notifyAll()的本质区别 收藏
转自:http://www.cnblogs.com/armyao/archive/2010/12/27/1917989.html
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/SuperMiner/archive/2007/04/22/1574615.aspx
notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。
两者的最大区别在于:
- notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
- notify则文明得多,它只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们。当第一个线程运行完毕以后释放对象上的锁此时如果该对象没有再次使用notify语句,则即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。
下面是一个很好的例子:
import java.util.*;
class Widget {
}
class WidgetMaker extends Thread {
List<Widget> finishedWidgets = new ArrayList<Widget>();
public void run() {
try {
while(true) {
Thread.sleep(5000); // 需要5秒钟才能新产生一个Widget
Widget w = new Widget();
/*
*
* 如果用notifyAll,则所有线程都企图冲出wait状态,第一个线程得到了锁,并取走了Widget,由于要间隔5秒针才new一个新的Widget,此时还没有新的Widget产生
* 并且解开了锁,然后第二个线程获得锁,运行finishedWidgets.remove(0),
* 但是由于finishedWidgets现在还是空的,于是产生异常
*
* ***********这就是为什么下面的那一句不能用notifyAll而是要用notify
*/
synchronized(finishedWidgets) {
finishedWidgets.add(w);
finishedWidgets.notify(); //这里只能是notify而不能是notifyAll
}
}
} catch(InterruptedException e) {
}
}
public Widget waitForWidget() {
synchronized(finishedWidgets) {
if(finishedWidgets.size()==0) {
try {
finishedWidgets.wait();
}catch(InterruptedException e){
}
}
return finishedWidgets.remove(0);
}
}
}
public class WidgetUser extends Thread {
private WidgetMaker maker;
public WidgetUser(String name,WidgetMaker maker) {
super(name);
this.maker = maker;
}
public void run() {
Widget w = maker.waitForWidget();
System.out.println(getName()+" got a widget");
}
public static void main(String[] args) {
WidgetMaker maker=new WidgetMaker();
maker.start();
new WidgetUser("Lenny",maker).start();
new WidgetUser("Moe",maker).start();
new WidgetUser("Curly",maker).start();
}
}
总结一下:
notifyAll(),使线程退出wait状态,变成等待该对象上的锁
notify只选择一个wait状态线程进行通知,并使它获得该对象上的锁,其他等待线程继续处在wait状态