1. 程式人生 > >設計模式-生產者消費者模式 常見場景: 某個模組負責產生資料,這些資料由另一個模組來負責處理。產生資料的模組,就形象地稱為生產者;而處理資料的模組,就稱為消費者。 該模式還需要有一個緩衝區處於生

設計模式-生產者消費者模式 常見場景: 某個模組負責產生資料,這些資料由另一個模組來負責處理。產生資料的模組,就形象地稱為生產者;而處理資料的模組,就稱為消費者。 該模式還需要有一個緩衝區處於生

常見場景:

某個模組負責產生資料,這些資料由另一個模組來負責處理。產生資料的模組,就形象地稱為生產者;而處理資料的模組,就稱為消費者。

該模式還需要有一個緩衝區處於生產者和消費者之間,作為一箇中介。生產者把資料放入緩衝區,而消費者從緩衝區取出資料

緩衝區作用

1. 解耦,生產者和消費者只依賴緩衝區,而不互相依賴

2. 支援併發和非同步

方式一,同步佇列

複製程式碼
/**
 * 生產者、消費者緩衝區
 */
public class Storage implements IStorage {

    private final int maxSize = 10;
    private Queue<Object> queue = new
LinkedList<Object>(); @Override public void put(Object obj) { synchronized (queue) { while (queue.size() > maxSize) { System.out.println("緩衝區已滿,不能進入"); try { queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } queue.add(obj); System.out.println(
"進入緩衝區"); queue.notifyAll(); } } @Override public Object get() { Object obj = null; synchronized (queue) { while (queue.size() <= 0) { System.out.println("緩衝區為空, 進入等待"); try { queue.wait(); }
catch (InterruptedException e) { e.printStackTrace(); } } obj = queue.poll(); System.out.println("離開緩衝區"); queue.notifyAll(); } return obj; } }
複製程式碼

方式二,可重入鎖

複製程式碼
public class Storage implements IStorage {

    private final int maxSize = 20;
    private LinkedList<Object> list = new LinkedList<Object>();
    private final Lock lock = new ReentrantLock();

    // 倉庫滿的條件變數
    private final Condition full = lock.newCondition();

    // 倉庫空的條件變數
    private final Condition empty = lock.newCondition();

    @Override
    public void put(Object obj) {
        lock.lock();

        while (list.size() >= maxSize) {
            try {
                System.out.println("緩衝區已滿,不能進入");
                // 生產阻塞
                full.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        list.add(obj);
        System.out.println("進入緩衝區");
        empty.signalAll();

        lock.unlock();
    }

    @Override
    public Object get() {
        lock.lock();

        while (list.size() <= 0) {
            try {
                System.out.println("緩衝區為空, 進入等待");
                // 消費阻塞
                empty.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        Object obj = list.remove();
        System.out.println("離開緩衝區");
        full.signalAll();

        lock.unlock();

        return obj;
    }
}
複製程式碼

方式三,阻塞佇列

複製程式碼
public class Storage implements IStorage {

    private LinkedBlockingQueue<Object> list = new LinkedBlockingQueue<Object>(10);

    @Override
    public void put(Object obj) {
        try {
            list.put(obj);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("進入緩衝區");
    }

    @Override
    public Object get() {
        Object obj = null;
        try {
            obj = list.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("離開緩衝區");
        return obj;
    }
}
複製程式碼