用執行個體揭示notify()和notifyAll()的本質差別 收藏
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();
}
}