多線程經典問題——生產者消費者(Java實現)

生產者消費者是多線程的一個經典問題,在併發編程中使用生產者和消費者模式能夠解決絕大多數併發問題。該模式通過平衡生產線程和消費線程的工作能力來提高程序的整體處理數據的速度。生產者消費者描述的是有一塊緩衝區作爲倉庫,生產者可以將產品放入倉庫,消費者則可以從倉庫中取走產品,即生產者和消費者在同一個時間段內共用同一個存儲空間。如果在正常情況下不加以協調,當存儲空間已滿,生產者佔用着它,消費者等着生產者讓出空間從而拿走產品,生產者等着消費者消費產品,從而向空間中添加產品。互相等待,從而發生死鎖。

解決生產者消費者問題的方法一般採用同步機制保證生產者和消費者之間的同步,這種方式有較高的效率,並且易於實現,代碼的可控制性較好,屬於常用的模式。

同步問題核心在於:如何保證同一資源被多個線程併發訪問時的完整性。常用的同步方法是採用信號或加鎖機制,保證資源在任意時刻至多被一個線程訪問。Java語言在多線程編程上實現了完全對象化,提供了對同步機制的良好支持。

生產者與消費者模型中,要保證以下幾點:

  1.  同一時間內只能有一個生產者生產 生產方法加鎖sychronized
  2.  同一時間內只能有一個消費者消費 消費方法加鎖sychronized
  3. 共享空間空時消費者不能繼續消費 消費前循環判斷是否爲空,空的話將該線程wait,釋放鎖允許其他同步方法執行
  4. 共享空間滿時生產者不能繼續生產 生產前循環判斷是否爲滿,滿的話將該線程wait,釋放鎖允許其他同步方法執行

生產者模型:一直生產,直到生產完10個。在生產過程中,如果庫存中存滿(1個)則停止生產(由clerk控制)

public class Producer implements Runnable {
    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println("生產者生產中...");
        for (int product = 1; product <= 1000; product++) {
            try {
                clerk.setProdect(product);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

消費者模型:不斷消費,直到消費10個。消費過程中,如果庫存有貨則消費,沒貨等待(clerk中wait())

public class Consumer implements Runnable {
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println("消費者購買中...");
        for (int i = 1; i <= 1000; i++) {
            try {
                clerk.getProdect();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

售貨員模型: 負責控制庫存,如果庫存沒貨:通知生產者開始生產(notify), 並且通知消費者等待(wait)如果庫存有貨:通知生產者停止生產(wait),並且通知消費者開始消費(notify)。notify() / notifyall() :通知 實質上相當於 喚醒。加synchronized 爲了保證,同一時刻只有一個生產者在生產,只有一個消費者在消費 。

public class Clerk {
    private int product = -1;

    public synchronized void setProdect(int product) throws InterruptedException {
        waitIfFull(); //如果滿,等待   被喚醒後繼續執行
        this.product = product;
        System.out.println("生產者生產 :" + product);
        notify();
    }
    public synchronized int getProdect() throws InterruptedException {
        waitIfEmpty(); //如果空,等待  被喚醒後繼續執行
        int p = this.product;
        System.out.println("消費者獲取 :" + p);
        this.product = -1;
        notify();
        return p;
    }

    private synchronized void waitIfEmpty() throws InterruptedException {
        if(product == -1){
            System.out.println("~~~~~~~消費者等待");
            wait();
        }
    }
    private synchronized void waitIfFull() throws InterruptedException {
        if(product != -1){
            System.out.println("~~~~~~~生產者等待");
            wait();
        }
    }
}

主類:

/**
 * Created by Amy on 2018/7/22.
 */
public class Demo_ProducerComsumer {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        new Thread(new Producer(clerk)).start();
        new Thread(new Consumer(clerk)).start();
    }
}

結果如下:

以上就是簡單生產者消費者模型。

參考文章:

https://blog.csdn.net/Dextrad_ihacker/article/details/53192046

http://www.cnblogs.com/0201zcr/p/4758533.html

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