說明
Java中,線程之間的通信主要是由java.lang.Object類提供的wait、notify和notifyAll這3個方法來完成:
①對象的wait方法被調用後,線程進入對象的等待隊列中,並釋放對象鎖,其它線程可以競爭使用此對象鎖;sleep方法使得一個線程進入睡眠狀態,但是線程所佔有的資源並沒有釋放。
②當對象的notify方法被調用,該方法會從對象的等待隊列中隨機取出一個線程來喚醒;notifyAll是喚醒等待隊列中所有線程,這些線程會與其它正在執行的線程共同競爭對象鎖。
③wait、notify和notifyAll這3個方法只能出現在synchronized作用的範圍內。當多個線程等待同一對象,而它們等待等待的條件不同時,應該使用notifyAll方法。notifyAll會導致性能下降,因爲不必要的線程也會被喚醒。而notify喚醒的線程有可能不是所期望的線程。
生產者與消費者問題
這裏,將使用某類資源(用類Goods表示)的線程稱爲消費者Consumer,產生同類資源的線程稱爲Producer。要想使得Consumer和Producer能夠協同工作,則它們應該遵循如下規則:
(1)只要緩衝區buffer有空間,生產者Producer就可向其中存放資源;當緩衝區buffer已滿時,則讓生產者Producer等待,放棄自己已獲取的對象鎖,進入等待隊列;
(2)只要緩衝區中有資源可用,消費者Consumer就可以從buffer中取出資源;當buffer爲空時,則讓Consumer等待,放棄自己已獲取的對象鎖,進入等待隊列;
(3)Producer和Consumer不能同時讀、寫buffer。所以對buffer進行操作的方法increase(生產資源)和decrease(消費資源)均需要使用synchronized進行同步。
/**
* Goods類,表示共享資源
*/
package com.hh.Producer.Consumer;
public class Goods {
private final int SIZE = 5;
private int buffer = 0;
/**
* 共享資源增加
*/
public synchronized int increase() {
if (buffer < SIZE) {
++buffer;
notify(); // 通知消費者可以消費
} else {
try {
wait(); // 生成者線程等待,直到消費者線程發出notify通知
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return buffer;
}
/**
* 共享資源減少
*/
public synchronized int decrease() {
if (buffer > 0) {
--buffer;
notify(); // 通知生產者可以生產
} else {
try {
wait(); // 消費者線程等待,直到生產者線程發出notify通知
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return buffer;
}
public int getGoodsSize() {
return SIZE;
}
}
/**
* Producer類,模擬生產者線程
*/
package com.hh.Producer.Consumer;
public class Producer implements Runnable {
private Goods goods;
public Producer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while (true) {
int goodsCount = goods.increase();
if (goodsCount != goods.getGoodsSize()) {
System.out.println("生產者生產了一件商品,目前商品數:" + goodsCount);
} else {
System.out.println("商品已滿,生產者等待");
}
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* Consumer類,模擬消費者
*/
package com.hh.Producer.Consumer;
public class Consumer implements Runnable {
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while (true) {
int goodsCount = goods.decrease();
if (goodsCount != 0) {
System.out.println("消費者消費了一件商品,目前商品數:" + goodsCount);
} else {
System.out.println("商品已空,消費者等待");
}
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* 測試生產者Producer與消費者Consumer線程之間的通信
*/
package com.hh.Producer.Consumer;
public class TestMain {
public static void main(String[] args) {
Goods goods = new Goods();
Producer producer = new Producer(goods);
Consumer consumer = new Consumer(goods);
new Thread(producer).start();
new Thread(consumer).start();
}
}
注意:是在共享資源Goods類中進行wait和notify操作,並不是在Producer或者Consumer類中。
對於這樣的問題,一定要自己動手寫示例代碼,這樣才能較好的理解線程之間的通信問題。