1. 程式人生 > 其它 >Java案例——生產者與消費者模式

Java案例——生產者與消費者模式

需求:某小區單元定製牛奶,送奶人員會將牛奶放入奶箱,該奶箱共能存放30瓶牛奶,居民從奶箱中取奶。請用程式實現這一過程

分析:

1.建立奶箱類:定義一個成員變數,表示是奶箱中的第幾瓶奶,提供存放牛奶和取出牛奶的方法

2.建立生產廠家類:實現Runable介面,重寫run方法,呼叫存放牛奶的方法

3.建立居民類:實現Runable介面,重寫run方法,呼叫取出牛奶的方法

4.建立測試類:

1.建立奶箱物件

2.建立生產廠家物件,並將奶箱物件作為構造方法引數傳遞,呼叫儲存牛奶的方法

3.建立居民物件,並將奶箱物件作為構造方法引數傳遞,呼叫取出牛奶的方法

4.建立兩個執行緒,分別把生產廠家物件、居民物件作為構造方法引數傳遞

5.啟動執行緒

奶箱類

package Demo041902;
public class Box {
  //定義一個成員變數,表示是奶箱中的第幾瓶奶,提供存放牛奶和取出牛奶的方法
  private int milk;
  //建立奶箱狀態,判斷是否為空
  Boolean state=false;
  //存放牛奶
  public synchronized void put(int milk){
      //先判斷奶箱是否為空,是:放奶入箱;否:休眠
      if (state){
          try {
              wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
      //state=false,放奶入箱
      this.milk=milk;
      System.out.println("生產廠家將第"+this.milk+"瓶奶放入奶箱");
      //修改狀態
      state=true;
      //喚醒執行緒
      notifyAll();
  }
  public synchronized void get(){
      //判斷奶箱是否為空,空的就休眠
      if (!state){
          try {
              wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
      //奶箱不空,就取奶
      System.out.println("居民取出第"+this.milk+"瓶奶");
      //取完後修改狀態
      state=false;
      //喚醒執行緒
      notifyAll();
  }

}

生產廠家類

package Demo041902;
public class producter implements Runnable {
  private Box b;
  public producter(Box b) {
      this.b=b;
  }
  //實現Runable介面,重寫run方法,呼叫存放牛奶的方法
  @Override
  public void run() {
      for (int i=1;i<=5;i++){
          b.put(i);
      }
  }
}

消費者類

package Demo041902;
public class consumer implements Runnable{
  private Box b;
  public consumer(Box b) {
      this.b=b;
  }
  //實現Runable介面,重寫run方法,呼叫取出牛奶的方法
  @Override
  public void run() {
      while(true){
          b.get();
      }
  }
}

測試類

package Demo041902;
public class Demo {
  public static void main(String[] args) {
      //建立奶箱物件
      Box b=new Box();
      //建立生產廠家物件,並將奶箱物件作為構造方法引數傳遞,呼叫儲存牛奶的方法
      producter p=new producter(b);
      //建立居民物件,並將奶箱物件作為構造方法引數傳遞,呼叫取出牛奶的方法
      consumer c=new consumer(b);
      //建立兩個執行緒,分別把生產廠家物件、居民物件作為構造方法引數傳遞
      Thread t=new Thread(p,"生產者");
      Thread t1=new Thread(c,"消費者");
      t.start();
      t1.start();
  }
}

容易出現的問題:

1.不判斷奶箱的狀態,會出現一直取最後一瓶奶

2.IllegalMonitorStateException:丟擲以表示執行緒已嘗試在物件的監視器上等待或通知其他執行緒等待物件的監視器,而不擁有指定的監視器。執行緒沒有同步會丟擲這個異常,需要在方法上加同步鎖

3.去除第一瓶奶後不往下走,執行緒休眠後沒有喚醒