更多 Java 并發(fā)編程方面的文章郭赐,請(qǐng)參見(jiàn)文集《Java 并發(fā)編程》
wait 和 notify 的功能
-
obj.wait():
- 如果當(dāng)前調(diào)用 obj.wait() 的線程并沒(méi)有獲得該對(duì)象 obj 上的鎖遣铝,則拋出異常 IllegalMonitorStateException
- 否則,當(dāng)前線程進(jìn)入 Waiting Pool 狀態(tài)
- 線程調(diào)用 obj.wait() 方法后舶治,在如下條件下,會(huì)從 Waiting Pool 狀態(tài)進(jìn)入 Waiting for monitor entry 狀態(tài):
- 該對(duì)象的 notify() 方法被調(diào)用
- 該對(duì)象的 notifyAll() 方法被調(diào)用
- obj.wait() 可以添加參數(shù)土思,例如 obj.wait(1000)闺阱,表示 1000 毫秒后自動(dòng)進(jìn)入 Waiting for monitor entry 狀態(tài)
- 線程被中斷
-
obj.notify():喚醒 一個(gè) 正在 Waiting Pool 中等待該對(duì)象的線程進(jìn)入 Waiting for monitor entry 狀態(tài)
- 具體是喚醒哪一個(gè)崖蜜?與優(yōu)先級(jí)無(wú)關(guān),由 JVM 決定
obj.notifyAll():喚醒 所有 正在 Waiting Pool 中等待該對(duì)象的線程進(jìn)入 Waiting for monitor entry 狀態(tài)
線程進(jìn)入 Waiting for monitor entry 狀態(tài)后衷笋,一旦該對(duì)象被解鎖芳杏,這些線程就會(huì)去競(jìng)爭(zhēng)。
wait 和 notify 的使用
- wait, notify, notifyAll 方法需要放在 synchronized 代碼塊中,因?yàn)楸仨毾全@得對(duì)象的鎖蚜锨!
- 由于線程可能在非正常情況下被意外喚醒档插,一般需要把 wait 方法放在一個(gè)循環(huán)中,例如:
synchronized(obj) {
while(some condition) {
try {
obj.wait();
} catch(...) {...}
}
}
通過(guò)wait和notify實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式
代碼如下:
public class ProducerCunsumer_Test {
private static final int MAX_CAPACITY = 10;
private static List<Object> goods = new ArrayList<Object>();
public static void main(String[] args) {
(new ProducerThread()).start();
(new ConsumerThread()).start();
}
static class ProducerThread extends Thread {
public void run() {
while (true) {
// 每隔 1000 毫秒生產(chǎn)一個(gè)商品
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
synchronized (goods) {
// 當(dāng)前商品滿了亚再,生產(chǎn)者等待
if (goods.size() == MAX_CAPACITY) {
try {
System.out.println("Goods full, waiting...");
goods.wait();
} catch (Exception e) {
}
}
goods.add(new Object());
System.out.println("Produce goods, total: " + goods.size());
// goods.notify() 也可以
goods.notifyAll();
}
}
}
}
static class ConsumerThread extends Thread {
public void run() {
while (true) {
// 每隔 500 毫秒消費(fèi)一個(gè)商品
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
synchronized (goods) {
// 當(dāng)前商品空了郭膛,消費(fèi)者等待
if (goods.size() == 0) {
try {
System.out.println("No goods, waiting...");
goods.wait();
} catch (Exception e) {
}
}
goods.remove(0);
System.out.println("Consume goods, total: " + goods.size());
// goods.notify() 也可以
goods.notifyAll();
}
}
}
}
}
在上面的代碼中,消費(fèi)商品的速度(500毫秒)快于生產(chǎn)商品的速度(1000毫秒)氛悬,依次輸出如下所示:
可以看出则剃,商品隊(duì)列經(jīng)常處于空的狀態(tài)。
No goods, waiting...
Produce goods, total: 1
Consume goods, total: 0
No goods, waiting...
Produce goods, total: 1
Consume goods, total: 0
No goods, waiting...
Produce goods, total: 1
Consume goods, total: 0
如果修改如捅,使得消費(fèi)商品的速度(500毫秒)慢于生產(chǎn)商品的速度(100毫秒)棍现,依次輸出如下所示:
可以看出,商品隊(duì)列經(jīng)常處于滿的狀態(tài)镜遣。
Produce goods, total: 1
Produce goods, total: 2
Produce goods, total: 3
Produce goods, total: 4
Produce goods, total: 5
Consume goods, total: 4
Produce goods, total: 5
Produce goods, total: 6
Produce goods, total: 7
Produce goods, total: 8
Consume goods, total: 7
Produce goods, total: 8
Produce goods, total: 9
Produce goods, total: 10
Goods full, waiting...
Consume goods, total: 9
Produce goods, total: 10
Goods full, waiting...
Consume goods, total: 9
Produce goods, total: 10
Goods full, waiting...
Consume goods, total: 9
Produce goods, total: 10
Goods full, waiting...