標籤:多線程 生產者與消費者
說明
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;}@Overridepublic 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 blocke.printStackTrace();}}}}
/** * Consumer類,類比消費者 */package com.hh.Producer.Consumer;public class Consumer implements Runnable {private Goods goods;public Consumer(Goods goods) {this.goods = goods;}@Overridepublic 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 blocke.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類中。
對於這樣的問題,一定要自己動手寫範例代碼,這樣才能較好的理解線程之間的通訊問題。