使用ReentrantLock模擬簡單生產者和消費者問題

使用ReentrantLock模擬簡單生產者和消費者問題


本文主要講述使用Java的ReentrantLock來實現模擬生產者-消費者的問題,主要經過以下5個過程來完成:
1. 生產商品,向存儲商品的數組中添加商品,該過程用ReentrantLock來加鎖。
2. 消費商品,從存儲商品的數組中消費商品,該過程同樣用ReentrantLock來加鎖。
3. 用一個生產線程來模擬進行生產商品的操作。
4. 用一個消費線程來模擬進行消費商品的操作。
5. 測試整個生產者-消費者問題的程序。


定義一個BoundedQueue類

BoundedQueue類主要有兩個方法add和reduce,對應模擬商品的生產和消費,代碼如下:

public class BoundedQueue<T> {
    private Object[] products;//存儲生產商品的數組products
    volatile int count;//數組products數組中已經存儲的商品數量
    int addIndex, reduceIndex; 
    Lock lock=new ReentrantLock();

    //notFull和notEmpty主要用於實現等待/通知功能
    Condition notFull=lock.newCondition();
    Condition notEmpty=lock.newCondition();

    //對類BoundedQueue的初始化操作
    public BoundedQueue(int size){
        super();
        products=new Object[size];
        count=0;
        addIndex=0;
        reduceIndex=0;
    }

    //模擬生產者生產商品
    public void add(T t) throws InterruptedException{
        lock.lock();
        try{
            while(count==products.length)
                notFull.await();//如果products數組已經裝滿,則生產線程進入等待隊列等待,釋放lock
            products[addIndex]=t;
            if(++addIndex==products.length)
                addIndex=0;
            count++;//products中增加一個新商品
            notEmpty.signal();//products中有商品,對消費線程進行通知
        }finally{
            lock.unlock();//釋放lock
        }
    }

    //模擬消費者消費商品
    public T reduce() throws InterruptedException{
        lock.lock();
        try{
            while(count==0)
                notEmpty.await();//如果products數組存儲的商品爲空,則消費線程進入等待隊列等待,釋放lock
            Object product=products[reduceIndex];//獲取的是Object類型需要強制類型轉換
            if(++reduceIndex==products.length)
                reduceIndex=0;
            count--;//products中消費一個商品
            notFull.signal();//products還未被沾滿,對生產線程進行通知
            return (T)product;
        }finally{
            lock.unlock();//釋放lock
        }
    }

    //獲取生產者線程
    public Thread getProduceThread(BoundedQueue<T> boundedQueue, Object products[])
    {
        Producer<T> producer=new Producer(boundedQueue, products);
        Thread produceThread=new Thread(producer,"produceThread");
        return produceThread;
    }

    //獲取消費者線程
    public Thread getConsumeThread(BoundedQueue<T> boundedQueue)
    {
        Consumer<T> consumer=new Consumer(boundedQueue);
        Thread consumeThread=new Thread(consumer,"consumeThread");
        return consumeThread;
    }
}

利用線程來模擬生產者

模擬生產者的代碼如下:

class Producer<T> implements Runnable{

    private BoundedQueue<T> boundedQueue;
    private Object[] readyProducts;//準備進行生產的商品

    //初始化Producer類
    public Producer(BoundedQueue<T> boundedQueue, Object[] readyProducts) {
        super();
        this.boundedQueue = boundedQueue;
        this.readyProducts=new Object[readyProducts.length];
        for(int i=0;i<readyProducts.length;i++)
            this.readyProducts[i]=readyProducts[i];
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<readyProducts.length;i++)
        {
            try {
                boundedQueue.add((T) readyProducts[i]);
                System.out.println(Thread.currentThread().getName()+" has produced ["+(T)readyProducts[i]+"]");//打印生產商品的信息
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        //}
    }

  }

}

利用線程來模擬消費者

模擬消費者的代碼如下:

class Consumer<T> implements Runnable{

    private BoundedQueue<T> boundedQueue;
    private boolean on;//作爲開關來關閉消費線程

    //初始化Consumer類
    public Consumer(BoundedQueue<T> boundedQueue) {
        super();
        this.boundedQueue=boundedQueue;
        this.on = true;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(on)
        {
            try {
                T product=boundedQueue.reduce();
                System.out.println(Thread.currentThread().getName()+" has consumed ["+product+"]");//打印消費的商品信息
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public void closeThread(){
        on=false;
    }
}

進行測試

測試代碼如下:

public static void main(String[] args) {
        BoundedQueue<String> boundedQueue=new BoundedQueue<>(3);
        String fruits[]=new String[]{"apple","banana","peach","watermelon","pear","grape"};
        Thread produceThread=boundedQueue.getProduceThread(boundedQueue, fruits);
        Thread consumeThread=boundedQueue.getConsumeThread(boundedQueue);
        produceThread.start();
        consumeThread.start();
}

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