生產者和消費者問題-----管程法

首先聲明,本人只是爲了鞏固知識而寫博客,如果你看了這篇博客對你有幫助,那麼我很開心,如果沒有幫助,那我也很遺憾,如果有錯誤很高興你指出來,只希望不要罵人,謝謝。

什麼是生產者和消費者

首先,我們都學過生物,顧名思義可以知道,生產者就是負責生產東西的,
消費者就是用來消費東西的。

生產者和消費者有什麼用

打個比方,我們去肯德基或者麥當勞點餐,那麼我們就是線程裏面的“消費者”,而那些負責製作食物的員工就是“生產者”
當我們點餐完成後,負責生產食物的人員不是去生產食物了,而是把之前生產好的食物搬到你的面前,然後你在開始進行用餐。
如果負責生產食物的人員發現食物的存儲量已經低於一個值,那麼這個時候,負責生產食物的人員就要開始去生產食物了,與此同時,消費者也要停止進餐,開始休息。

什麼是緩衝區

這個很容易理解就相當於裝食物的容器,我們去肯德基麥當勞點餐的時候,是不是會看見有一個大大的容器,裏面就是裝食物的,當我們把食物消滅到一定數量的時候,工作人員又開始繼續製作食物了。

看圖理解

在這裏插入圖片描述

代碼實現(容器)

class RQ //定義一個容器類
{
    Egg[] eggs=new Egg[10];  //new一個雞蛋數組就十個吧,雞蛋類會在下面寫到
    int count =1; //一開始有一個雞蛋
    public synchronized void push(Egg egg ) throws InterruptedException {
        if(count==eggs.length) {
            this.wait();//如果雞蛋的數量等於數組的長度,也就是十,線程開始等待,這個時候下面的代碼不會執行
        }
        //當這個線程被喚醒,開始執行
        eggs[count]=egg;//
        count++;
        this.notifyAll();

    }

    public synchronized Egg pop() throws InterruptedException {
        if(count==1)
        {
            this.wait();//如果雞蛋只有一個,那麼線程開始等待
        }
        //線程被喚醒後開始執行
        count--;
        Egg egg=eggs[count];
        this.notifyAll();
        return egg;
    }

}


代碼實現(生產者)

class scz implements Runnable
{
    RQ rq =new RQ();//先new一個容器
    public scz(RQ rq) {
        this.rq = rq;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
             System.out.println("生產了第--->"+i+"個雞蛋");
            try {
                rq.push(new Egg(i));//沒生產一個雞蛋,就調用rq函數的push,並且把i傳入到Egg的id裏面;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }
}

代碼實現(消費者)

class xfz implements Runnable
{
    RQ rq =new RQ();//new一個容器
    public xfz(RQ rq) {
        this.rq = rq;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            try {
                System.out.println("消費了第--->"+rq.pop().id+"個雞蛋");
                //如果是寫i的話那麼消費者吃掉的雞蛋就和生產者生產的數量沒關係
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

代碼實現(雞蛋)

class Egg
{
    int id=0;

    public Egg(int id) {
        this.id = id;
    }
}

全部代碼總和

package Thread;

public class mytest01 {
    public static void main(String[] args) {
        RQ rq=new RQ();
        scz s=new scz(rq);
        xfz x =new xfz(rq);
        Thread t1=new Thread(s);
        Thread t2=new Thread(x);
        t1.start();
        t2.start();

    }
}
class scz implements Runnable
{
    RQ rq =new RQ();

    public scz(RQ rq) {
        this.rq = rq;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
             System.out.println("生產了第--->"+i+"個雞蛋");
            try {
                rq.push(new Egg(i));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }
}

class xfz implements Runnable
{
    RQ rq =new RQ();
    public xfz(RQ rq) {
        this.rq = rq;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            try {
                System.out.println("消費了第--->"+rq.pop().id+"個雞蛋");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

class RQ
{
    Egg[] eggs=new Egg[10];
    int count =1;
    public synchronized void push(Egg egg ) throws InterruptedException {
        if(count==eggs.length) {
            this.wait();
        }
        eggs[count]=egg;
        count++;
        this.notifyAll();

    }

    public synchronized Egg pop() throws InterruptedException {
        if(count==1)
        {
            this.wait();
        }
        count--;
        Egg egg=eggs[count];

        this.notifyAll();
        return egg;
    }

}

class Egg
{
    int id=0;

    public Egg(int id) {
        this.id = id;
    }
}

結果

在這裏插入圖片描述

每一次運行結果都會是不一樣的,因爲每次cpu調度的時間不一樣,結果就不一樣,同時,消費者不會按照生產者生產的順序吃食物,是拿起來就是隨便吃,可能先吃第四個的時候,生產者下一波食物就生成了,他就直接吃了下一波的食物。

總結

總的來說,只需要控制好變量,這個並不是很難理解,但是要鎖對地方,如果鎖錯地方那麼就會出現錯誤的結果,這個是我第一次寫博客,寫的不好還請見諒,希望可以幫助到你。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章