生產者與消費者的問題


目標問題:生產者與消費者問題---之代碼的實現;
生產模式:2個生產者--2個消費者--一個緩衝區;

因工作需求,最近在學習java,所以就找到一些問題來練手,這就來到了生產者與消費者的問題!

具體實現代碼如下:

import java.lang.*;
public class ProducerConsumer{
    public static void main(String[] args){
        SyncStack ss = new SyncStack();
        Producer p = new Producer(ss);
        Consumer c = new Consumer(ss);
        new Thread(p).start();
        new Thread(p).start();
        new Thread(c).start();
        new Thread(c).start();
        System.out.println("總共生產了: " + ss.getTotalProducts());
        System.out.println("總共消費了: " + ss.getTotalConsumer());
    }
}
class Product{
    int id;
    Product(int id){
        this.id = id;
    }
    public String toString(){
        return "Product" + id;
    }
}
class SyncStack{
    int index = 0;
    int totalProducts = 0;
    int totalConsumer = 0;
    Product[] arrProduct = new Product[6];
    //生產產品;
    public synchronized void push(Product pd){
        while(index == arrProduct.length){
            try{
                this.wait();      //只有鎖住這個線程了才能wait(),是Object這個類的wait;wait的時候,該鎖就屬於自己了;
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        this.notifyAll();
        arrProduct[index] = pd;
        index ++;
        totalProducts++;
    }
    //消費者消費產品;
    public synchronized Product pop(){
        while(0 == index){
            try{
                this.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        this.notifyAll();
        index--;
        totalConsumer++;
        return arrProduct[index];
    }
    public int getRemain(){
        return index;
    }
    public int getTotalProducts(){
        return totalProducts;
    }
    public int getTotalConsumer(){
        return totalConsumer;
    }
}
class Producer implements Runnable{
    SyncStack ss = null;
    int ProducerNum = 20;
    Thread current = Thread.currentThread();
    Producer(SyncStack ss){
        this.ss = ss;
    }
    public void run(){
        for(int i = 0; i < ProducerNum; i++){
            Product pd = new Product(i);
            ss.push(pd);
            System.out.println(current.getId() + "生產了,存入倉庫:" + pd);
            try{
                Thread.sleep((int)(Math.random() * 1000));
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}
class Consumer implements Runnable{
    SyncStack ss = null;
    int ConsumerNum = 20;
    Thread current = Thread.currentThread();
    Consumer(SyncStack ss){
        this.ss = ss;
    }
    public void run(){
        for(int i = 0; i < ConsumerNum; i++){
            Product pd = ss.pop();
            System.out.println(current.getId() + "從倉庫取出,消費了:" + pd);
            System.out.println("倉庫產品還剩:" + ss.getRemain());
            try{
                Thread.sleep(1000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

問題解決:
 <1> 關係分析。生產者和消費者對緩衝區互斥訪問是互斥關係,同時生產者和消費者又是一個相互協作的關係,只有生產者生產之後,消費者才能消費,他們也是同步關係;
 <2> 整理思路。這裏比較簡單,只有生產者和消費者兩個進程,正好是這兩個進程存在着互斥關係和同步關係。那麼需要解決的是互斥和同步的位置;
 第一.從緩衝區取出產品和向緩衝區投放產品必須是互斥進行的,這裏用synchronized關鍵字同步鎖來實現;
 第二.生產者要等待緩衝區有空間,這樣纔可以生產投放產品,消費者要等待緩衝區不爲空,這樣纔可以取出產品進行消費。主要用wait和notify來實現
 1、如果沒有wait() 和 notify() / notufyAll() 可能會產生死鎖;因爲生產滿了就停止生產,假如消費者消費完了也不提醒生產者,這樣兩個線程就都等着了,會產生死鎖!
 2、while不能換成if,因爲如果倉庫滿了,這時候生產者睡眠wait,假如此時來了一個異常,這樣程序就會繼續執行,但是倉庫還是滿的,因爲消費者沒有消費,所以這時會產生溢出;
 3、wait 和sleep的區別:
 wait:如果加鎖了,別人可以訪問鎖定的對象;父類是object
 sleep:加鎖了,不釋放,別人不能訪問其鎖定的對象;

 運行結果:

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