wait(),notify(),notifyAll()不屬於
Thread類,而是屬於
Object基礎類,也就是說每個對象都有
wait(),notify(),notifyAll()的功能.因為每個對象都有鎖,鎖是每個對象的基礎,當然操作鎖的方法也是最基礎了。
wait導致當前的線程等待,直到其他線程調用此對象的
notify() 方法或
notifyAll() 方法,或被其他線程中斷。wait只能由持有對像鎖的線程來調用。
notify喚醒在此對象監視器上等待的單個線程。如果所有線程都在此對象上等待,則會選擇喚醒其中一個線程(隨機)。直到當前的線程放棄此對象上的鎖,才能繼續執行被喚醒的線程。同Wait方法一樣,notify只能由持有對像鎖的線程來調用.notifyall也一樣,不同的是notifyall會喚配所有在此對象鎖上等待的線程。
"只能由持有對像鎖的線程來調用"說明wait方法與notify方法必須在同步塊內執行,即synchronized(obj)之內.再者synchronized代碼塊內沒有鎖是寸步不行的,所以線程要繼續執行必須獲得鎖。相輔相成。
看一個很經典的例子(生產者與消費者):
首先是消費者線程類:
代碼如下:
import java.util.List;
public class Consume implements Runnable {
private List container = null;
private int count;
public Consume(List lst) {
this.container = lst;
}
public void run() {
while (true) {
synchronized (container) {
if (container.size() == 0) {
try {
container.wait();// 容器為空,放棄鎖,等待生產
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
container.remove(0);
container.notify();
System.out.println("我吃了" + (++count) + "個");
}
}
}
}
接下來是生產者線程類:
代碼如下:
import java.util.List;
public class Product implements Runnable {
private List container = null;
private int count;
public Product(List lst) {
this.container = lst;
}
public void run() {
while (true) {
synchronized (container) {
if (container.size() > MultiThread.MAX) {
// 如果容器超過了最大值,就不要在生產了,等待消費
try {
container.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
container.add(new Object());
container.notify();
System.out.println("我生產了" + (++count) + "個");
}
}
}
}
最後是測試類:
代碼如下:
import java.util.ArrayList;
import java.util.List;
public class MultiThread {
private List container = new ArrayList();
public final static int MAX = 5;
public static void main(String args[]) {
MultiThread m = new MultiThread();
new Thread(new Consume(m.getContainer())).start();
new Thread(new Product(m.getContainer())).start();
}
public List getContainer() {
return container;
}
public void setContainer(List container) {
this.container = container;
}
}
運行結果如下所示:
代碼如下:
我生產了1個
我吃了1個
我生產了2個
我生產了3個
我生產了4個
我生產了5個
我生產了6個
我生產了7個
我吃了2個
我生產了8個
我吃了3個
我生產了9個
我吃了4個
我吃了5個
我吃了6個
我吃了7個
我吃了8個
我生產了10個
我生產了11個
我吃了9個
我生產了12個
我吃了10個
......