生产者消费者案例
目錄
- 前言
- 一、案例描述
- 二、創建快遞柜
- 三、創建生產者類
- 四、創建消費者類
- 五、測試類
- 總結
前言
生產者消費者模式屬于一種經典的多線程協作的模式,弄清生產者消費者問題能夠讓我們對于多線程編程有更深刻的理解,下面,為大家分享一個生產者消費者的案例。
一、案例描述
這里以快遞為例,假設有一個快遞柜,用來存快遞,然后有快遞員和取件人,快遞員往快遞柜里存快遞,取件人從快遞柜中取走快遞。快遞員作為生產者,取件人作為消費者,當兩者在一個時間段同時進行多次自己的操作時,很明顯這就是多線程編程的生產者消費者實例了。在這里,我們希望快遞員(生產者)存入一個快遞,取件人(消費者)就拿走一個快遞,如果快遞還沒有被取走,那么生產者應該等待,而如果快遞柜里沒有快遞,則消費者應該等待。
首先來明確一下,這個案例我們需要準備:
(1) 創建快遞柜對象作為共享數據區域
(2) 創建生產者,把快遞柜對象作為參數傳遞至構造方法,因為生產者需要完成存快遞的操作
(3)創建消費者,把快遞柜作為對象傳遞至構造方法,因為消費者需要完成取快遞的操作
(4)創建兩個線程,將生產者和消費者對象分別作為參數傳遞至線程的構造方法,然后啟動線程
下面是具體實現:
二、創建快遞柜
代碼如下:
public class Box {//定義成員變量表示第幾個快遞(快遞序號)private int express;//定義一個成員變量用于表示快遞柜的狀態private boolean flag = false;//存快遞public synchronized void put(int express) {//如果有快遞,那么快遞員應該等待取件人來取快遞if (flag) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果沒有快遞,那么快遞員就存入快遞this.express = express;System.out.println("快遞員將第" + this.express + "個快遞存入了快遞柜");//別忘了存完修改快遞柜的狀態flag = true;//修改完快遞柜狀態后,喚醒其他在等待的線程notifyAll();}//取快遞public synchronized void get() {//如果有快遞,那么取件人就取走快遞if (flag) {System.out.println("取件人取出了第" + this.express + "個快遞");flag = false;notifyAll();} else {//沒有快遞,那么取件人就等待try {wait();} catch (InterruptedException e) {e.printStackTrace();}}} }說明:
如之前的分析,我們創建了一個Box類當做快遞柜,除了表示快遞序號的成員變量以外和對應的存快遞、取快遞方法外,還包括一個用來標記快遞柜狀態的變量,因為線程執行時需要這個標記來判斷是該執行還是等待。存快遞和取快遞的方法都加上了sychronized變成了同步方法,因為用于等待的wait()方法和喚醒的notifyAll()方法要在sychronized塊中使用,否則會拋出 IllegalMonitorStateException異常而無法執行。
三、創建生產者類
代碼如下:
public class Producer implements Runnable{private Box b;public Producer(Box b){this.b = b;}@Overridepublic void run() {for(int i = 1 ;i<11;i++){b.put(i);}} }說明:
快遞員當做生產者類,它實現了Runnable接口,重寫了run()方法,并且有一個Box類型的成員變量,和一個以這個成員變量為參數的構造方法,因為在這個類中要調用存快遞的操作。在這里,run()方法里一共存入了10次快遞。
四、創建消費者類
代碼如下:
public class Customer implements Runnable{private Box b ;public Customer(Box b){this.b = b;}@Overridepublic void run() {while(true){b.get();}} }說明:
同生產者類一樣,消費者(取件人)類也實現了Runnable接口,重寫了run()方法,同樣有一個Box類型的成員變量,和一個以這個成員變量為參數的構造方法,因為這個類里會調用取快遞的操作。由于能取快遞的次數是由生產者(快遞員)存入多少快遞決定的,所以這里我們直接用while循環就好了。
五、測試類
在測試類中,我們分別創建快遞柜、生產者和消費者的對象,將快遞柜對象作為參數分別傳入生產者和消費者創建時的構造方法。然后創建兩個線程,分別將生產者和消費者對象作為構造方法的參數傳遞,最后啟動線程,觀察結果。
代碼如下:
public class BoxDemo {public static void main(String[] args) {//創建快遞柜對象Box box = new Box();//創建生產者和消費者對象Producer p = new Producer(box);Customer c = new Customer(box);//創建兩個線程Thread t1 = new Thread(p,"生產者線程");Thread t2 = new Thread(c,"消費者線程");//啟動線程t1.start();t2.start();} }執行結果:
可以看到,快遞員和取件人有序地完成了10個快遞的存和取。
總結
以上就是一個簡單的生產者和消費者的案例,從這里面我們可以看出,這種模式除了生產者、消費者以外,還有一個很重要的中介的數據緩存區,也就是案例中的快遞柜,生產者往里面“丟”,消費者從里面“拿”,這樣三者才構成了完整的生產者消費者模式。
總結
- 上一篇: nn.Module、nn.Sequent
- 下一篇: 指北针软件