手寫一個生產者/消費者模式

學了生產者/消費者模式這麼久,今天終於來實現一下了,寫以前先複習一下生產者/消費者。java

生產者/消費者模式在操做系統中是個經典的進程同步問題,能夠使用「信號量」機制來解決,須要注意的點在下面有提到。緩存

寫以前先分析一下須要作的事情:ide

  1. 定義一個緩存隊列,選擇一個集合作緩存,緩存裏面只作兩件事情,存數據和取數據
  2. 定義一個生產者線程生產數據,而後存到緩存裏
  3. 定義一個消費者從緩存取數據

方式一

用LinkedHashMap當緩存,synchronized做爲同步鎖測試

定義一個緩存隊列this

public class PublicQueue<T> {

    //數據插入的下標
    private int putIndex = 0;
    //最大容量
    private int maxCount = 50;

    //緩衝區
    private LinkedHashMap<Integer, T> linkedHashMap = new LinkedHashMap<>();


    /** * 往阻塞隊列添加數據 * @param msg */
    public synchronized void put(T msg) {
        //若是緩存的數據達到maxCount,阻塞
        if (linkedHashMap.size() == maxCount) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            //沒有滿,就喚醒其餘全部線程
            notifyAll();
        }

        //往緩存裏面存數據
        linkedHashMap.put(putIndex, msg);
        System.out.println("生產一個產品,當前商品下標爲:"+putIndex+"===文本爲:"+msg+"===緩存長度爲:"+linkedHashMap.size());
        //更新putIndex
        putIndex = (putIndex + 1 >= maxCount) ? (putIndex + 1) % maxCount : putIndex + 1;
    }


    /*** * 從阻塞隊列取數據 * @return */
    public synchronized T get() {
        //若是阻塞隊列爲空,就阻塞消費者
        if (linkedHashMap.size() == 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            notifyAll();
        }

        //經過Iterator取數據,確保取出的數據是有序的
        Iterator iterator = linkedHashMap.entrySet().iterator();
        T t = null;
        if (iterator.hasNext()) {
            Map.Entry<Integer, T> entry = (Map.Entry<Integer, T>) iterator.next();
            t = entry.getValue();
            int index = entry.getKey();
            linkedHashMap.remove(index);
            System.out.println("消費一個產品,當前商品下標爲:"+index+"===文本爲:"+ t +"===緩存長度爲:"+linkedHashMap.size());
        }
        return t;
    }
}
複製代碼

定義一個生產者線程spa

public class Provider extends Thread{

    private PublicQueue publicQueue;

    public Provider(PublicQueue publicQueue) {
        this.publicQueue = publicQueue;
    }

    @Override
    public void run() {
        for (int i = 0; i < 60; i++) {
            publicQueue.put(String.valueOf(i));
        }
    }
}
複製代碼

定義一個消費者線程操作系統

public class Consumer extends Thread{

    private PublicQueue publicQueue;

    public Consumer(PublicQueue publicQueue) {
        this.publicQueue = publicQueue;
    }

    @Override
    public void run() {
        for (; ; ) {
            publicQueue.get();
        }
    }
}
複製代碼

測試線程

public class ProviderConsumerTest {
    public static void main(String[] args) {
        PublicQueue publicQueue = new PublicQueue();
        Provider provider = new Provider(publicQueue);
        Consumer consumer = new Consumer(publicQueue);
        provider.start();
        consumer.start();
    }
}
複製代碼

方式二

這個方式也是比較簡單的,直接使用Java提供的阻塞隊列便可code

public class PublicQueue<T> {
    //緩衝區
    private BlockingDeque<T> blockingDeque = new LinkedBlockingDeque<>(50);

    public void add(T msg){

        try {
            blockingDeque.put(msg);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("生產一個產品,當前商品下標爲:"+"===文本爲:"+msg);
    }

    public T get(){

        T t = null;
        try {
            t = blockingDeque.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("消費一個產品,當前商品下標爲:"+"===文本爲:"+t);
        return t;
    }
}
複製代碼
相關文章
相關標籤/搜索