對(duì)多線程編程里wait() notify()的精確論述:這一對(duì)方法直接隸屬于 Object 類,也就是說(shuō),所有對(duì)象都擁有這一對(duì)方法。
初看起來(lái)這十分不可思議,但是實(shí)際上卻是很自然的,因?yàn)檫@一對(duì)方法阻塞時(shí)要釋放占用的鎖,而鎖是任何對(duì)象都具有的,調(diào)用任意對(duì)象的 wait()
方法導(dǎo)致線程阻塞,并且該對(duì)象上的鎖被釋放。而調(diào)用 任意對(duì)象的notify()方法則導(dǎo)致因調(diào)用該對(duì)象的 wait()
方法而阻塞的線程中隨機(jī)選擇的一個(gè)解除阻塞(但要等到獲得鎖后才真正可執(zhí)行)。
其次,前面敘述的所有方法都可在任何位置調(diào)用,但是這一對(duì)方法卻必須在 synchronized
方法或塊中調(diào)用,理由也很簡(jiǎn)單,只有在synchronized
方法或塊中當(dāng)前線程才占有鎖,才有鎖可以釋放。同樣的道理,調(diào)用這一對(duì)方法的對(duì)象上的鎖必須為當(dāng)前線程所擁有,這樣才有鎖可以釋放。因此,這一對(duì)方法調(diào)用
必須放置在這樣的 synchronized
方法或塊中,該方法或塊的上鎖對(duì)象就是調(diào)用這一對(duì)方法的對(duì)象。若不滿足這一條件,則程序雖然仍能編譯,但在運(yùn)行時(shí)會(huì)出現(xiàn)
IllegalMonitorStateException 異常
下面的這個(gè)例子很好的反映了wait()和notify()或者notifyAll()的用法
public class Main {
/**
* 這是5個(gè)工人干活的例子,因?yàn)楣と说男什灰粯?效率高的先完成任務(wù),
* 然后休息,當(dāng)最后的一個(gè)工人完成工作的時(shí)候通知所有的人,所有工人又重新開(kāi)始干活了;
* 線程與線程組編制成了一個(gè)線程樹(shù),樹(shù)干是線程組,樹(shù)葉是線程,而這顆樹(shù)的根就是系統(tǒng)a線程組.
*/
public static void main(String[] args) throws InterruptedException {
Resource r = new Resource(4);
ThreadGroup tg = new ThreadGroup("GT");
new Thread(tg, new Worker(r,8)).start();
new Thread(tg, new Worker(r,12)).start();
new Thread(tg, new Worker(r,22)).start();
new Thread(tg, new Worker(r,16)).start();
new Thread(tg, new Worker(r,20)).start();
new Thread(tg, new Manager()).start();
}
}
public class Worker implements Runnable {
private Resource r;
/**
* the mission
*/
private int efficiency;
public Worker(Resource r,int efficiency){
this.r = r;
this.efficiency = efficiency;
}
public void run() {
int i = 0;
while(true){
System.out.println(Thread.currentThread()+" is working");
i ++;
if(i == efficiency){
i = 0;
r.waitForAll();
}
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
public class Worker implements Runnable {
private Resource r;
/**
* the mission
*/
private int efficiency;
public Worker(Resource r,int efficiency){
this.r = r;
this.efficiency = efficiency;
}
public void run() {
int i = 0;
while(true){
System.out.println(Thread.currentThread()+" is working");
i ++;
if(i == efficiency){
i = 0;
r.waitForAll();
}
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}