線程——Java生產(chǎn)者消費(fèi)者問題詳解

gghh######生產(chǎn)者消費(fèi)者問題是操作系統(tǒng)中的經(jīng)典問題,先用聲明Thread子類的方法來實(shí)現(xiàn)

問題:

顧客去包子店中買包子
包子每次只能生產(chǎn)一個(gè)只能消費(fèi)一個(gè)
包子有天津狗不理和無錫灌湯包兩類,價(jià)格分別是20元和10元。
蒸籠中沒有包子,店家才能生產(chǎn),否則等待。
蒸籠中有包子,顧客才能消費(fèi),否則等待。
請實(shí)現(xiàn)此過程

圖解.png

首先要設(shè)計(jì)類

  • 包子是生產(chǎn)者和消費(fèi)者共有的,作為一類,包子的成員變量是其品牌,價(jià)格,存在狀態(tài),包子的存在狀態(tài)需要更改,所以要有一個(gè)get和set方法
  • 生產(chǎn)者類:要有一個(gè)生產(chǎn)包子的方法,方法邏輯是有包子則等待,沒包子才生產(chǎn),生產(chǎn)完成了更改包子狀態(tài),通知消費(fèi)者
  • 消費(fèi)者類類:要有一個(gè)消費(fèi)包子的方法,方法邏輯是有包子才消費(fèi),消費(fèi)完成后更改包子狀態(tài),通知生產(chǎn)者繼續(xù)生產(chǎn)包子
  • 一個(gè)測試類,創(chuàng)建包子對象,包子是共享數(shù)據(jù),生產(chǎn)者消費(fèi)者需要知道包子的具體狀態(tài),所以生產(chǎn)者消費(fèi)者中需要有傳入包子對象的構(gòu)造方法

1. 先寫包子類

/**
 * @author Joker
 */
public class BaoZi
{
    String name;
    int price;
    boolean flag = false;

//獲取和設(shè)置包子的成員變量
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public int getPrice()
    {
        return price;
    }
    public void setPrice(int price)
    {
        this.price = price;
    }
    public boolean isFlag()
    {
        return flag;
    }
    public void setFlag(boolean flag)
    {
        this.flag = flag;
    }
    
    /**
     * 包子的有參構(gòu)造方法,用于生產(chǎn)包子時(shí)創(chuàng)建相應(yīng)品牌價(jià)格的包子對象
    */
    public BaoZi(String name, int price)
    {
        super();
        this.name = name;
        this.price = price;
    }
    
    /**
     * 包子的無參構(gòu)造
     */
    public BaoZi()
    {
    }
    
      /**
      * 生產(chǎn)包子方法,用于生產(chǎn)者調(diào)用,同步線程聲明synchronized 關(guān)鍵字
      * 包子有不同的品牌和價(jià)格,所以需要傳入對應(yīng)的成員變量值
      */
    public synchronized void produce(String name, int price)
    {
        if (flag)
        {
            try
            {
                wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }   

    //更改傳遞包子的屬性 
        this.name = name;
        this.price = price; 

    //更改包子的狀態(tài)并通知消費(fèi)者
        flag = true;
        notify();
}

     /**
      * 消費(fèi)包子方法,用于消費(fèi)者調(diào)用,同步線程聲明synchronized 關(guān)鍵字
      * 消費(fèi)者只能消費(fèi)生產(chǎn)者已經(jīng)生產(chǎn)好的包子,所以無需更改包子的成員參數(shù)
      */
    public synchronized void consume()
    {
        if (!flag)
        {
            try
            {
                wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        //表明正在消費(fèi)何種包子(必須是剛才生產(chǎn)者已經(jīng)生產(chǎn)好的)
        System.out.println("正在消費(fèi)" + getName() + ":" + getPrice() + "元");

          //更改包子存在狀態(tài)并通知生產(chǎn)者繼續(xù)生產(chǎn)
        flag = false;
        notify();
    }
    
}

2. 生產(chǎn)者類

public class Producer extends Thread
{
    BaoZi baoZi;
    /**
     * @param 構(gòu)造方法接收包子對象進(jìn)行通信
     */

    public Producer(BaoZi baoZi)
    {
        this.baoZi = baoZi;
    }

    @Override
    public void run()
    {
        super.run();
        // i計(jì)數(shù)來生產(chǎn)不同類型的包子,偶數(shù)次時(shí)生產(chǎn)天津狗不理
        int i = 0;
        while (true)
        {
            if (i % 2 == 0)
            {
                // 調(diào)用produce方法生產(chǎn)對應(yīng)的包子并輸出
                baoZi.produce("天津狗不理", 10);
                System.out.println("正在生產(chǎn)" + baoZi.getName() + ":" + baoZi.getPrice() + "元");
            }
            else
            {
                baoZi.produce("無錫灌湯包", 20);
                System.out.println("正在生產(chǎn)" + baoZi.getName() + ":" + baoZi.getPrice() + "元");
            }
            i++;
        }
    }
}

3. 消費(fèi)者類

public class Consumer extends Thread
{
    BaoZi baoZi;
    /**
     * 構(gòu)造方法 傳入baozi對象進(jìn)行通信
     */
    public Consumer(BaoZi baoZi2)
    {
        baoZi = baoZi2;
    }

    @Override
    public void run()
    {       
       super.run();
        while (true)
        {
            baoZi.consume();
        }
    }
}

4. 測試類

public class TestMain
{
    public static void main(String[] args)
    {
        Baozi baozi = new Baozi(null, 0);
        Producer producer = new Producer(baozi);
        Customer customer = new Customer(baozi);
               //啟動線程
        producer.start();
        customer.start();
    }
}

5. 運(yùn)行結(jié)果

控制臺輸出.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,991評論 19 139
  • 題圖 兩個(gè)線程一個(gè)生產(chǎn)者個(gè)一個(gè)消費(fèi)者 需求情景 涉及問題 代碼實(shí)現(xiàn)(共三個(gè)類和一個(gè)main方法的測試類) 多個(gè)線程...
    極樂君閱讀 514評論 0 4
  • 【 線程間的通訊 wait()在對象上等待,等待通知(在等待過程中釋放對象鎖、等待必須在同步塊內(nèi)、這個(gè)對象就是同步...
    征程_Journey閱讀 716評論 0 0
  • 逃一節(jié)自習(xí),出去逛逛 天地間什么都沒有,只有我 和這傘下的世界 小雨淅瀝,打在傘上沙沙 靜靜的走,走著鬼魅的步伐 ...
    林白駒閱讀 257評論 0 0
  • 白襯衫,黑碎發(fā),當(dāng)年你倚墻淺笑,踏亂我整個(gè)年華。 蘇倚楠以為自己的青春就這么在考卷、動漫中荒廢了,但凡事無絕對,就...
    是青祁吖閱讀 320評論 0 2