Java併發編程初級篇(十二):使用wait和notify生產者消費者問題

在這裏咱們模擬一個生產者消費者問題。定義一個緩衝區,生產者生產數據並存入緩衝區,消費者從緩衝區中消費數據。緩衝區有固定大小,當緩衝區達到最大時生產者被掛起並等待消費者消費數據後再嘗試將生產的數據加入緩衝區;當緩衝區數據量爲0時,消費者被掛起直到有生產者向緩衝區中存入數據。java

咱們能夠看到這個緩衝區是一個公共變量,因此緩衝區中數據的存放和取出都必須放置在一段synchronized修飾的同步代碼中。ide

Java API的Object類提供了一組方法wait(),notify()和nofityAll()用於實現這個例子。this

示例代碼:線程

首先咱們建立一個類來模擬實現一個阻塞數據緩衝池,這個緩衝池有一個鏈表結構用於緩衝數據,有一個整形變量用於定義數據緩衝區大小。一個set()方法用於模擬生產者向緩衝區內加入數據,一旦數據緩衝區滿則掛起,成功插入數據後喚起全部消費者線程。一個get()方法用於模擬消費者從緩衝區中消費數據,一旦數據緩衝區空了則掛起,成功消費數據後喚起全部生產者線程。日誌

public class EventStorage {
    private int maxSize;
    private LinkedList<Date> storage;

    public EventStorage() {
        maxSize = 10;
        storage = new LinkedList<Date>();
    }

    public void set() {
        synchronized (Main.producerController) {
            while (storage.size() == maxSize) {
                try {
                    Main.producerController.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            storage.add(new Date());
            System.out.printf("%s: Add one. storge size: %d.\n", Thread.currentThread().getName(), storage.size());
        }

        synchronized (Main.consumerController) {
            Main.consumerController.notifyAll();
        }
    }

    public void get() {
        synchronized (Main.consumerController) {
            while (storage.size() == 0) {
                try {
                    Main.consumerController.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.printf("%s: Get one %s. Storge size: %d.\n", Thread.currentThread().getName(), storage.poll(), storage.size());
        }

        synchronized (Main.producerController) {
            Main.producerController.notifyAll();
        }
    }
}

建立兩個線程類用於模擬生產者和消費者。code

public class Producer implements Runnable{
    private EventStorage eventStorage;

    public Producer(EventStorage eventStorage) {
        this.eventStorage = eventStorage;
    }

    @Override
    public void run() {
        eventStorage.set();
    }
}
public class Consumer implements Runnable{
    private EventStorage eventStorage;

    public Consumer(EventStorage eventStorage) {
        this.eventStorage = eventStorage;
    }

    @Override
    public void run() {
        eventStorage.get();
    }
}

定義主方法類,在這裏咱們啓動20個消費者線程與20個生產者線程,其中生產者速度快,消費者速度慢。這樣會致使生產者線程阻塞,等待消費者消費數據後被喚醒。get

public class Main {
    public static final Object producerController = new Object();
    public static final Object consumerController = new Object();

    public static void main(String[] args) {
        EventStorage eventStorage = new EventStorage();

        Producer producer = new Producer(eventStorage);
        Consumer consumer = new Consumer(eventStorage);

        Thread[] threads1 = new Thread[20];
        Thread[] threads2 = new Thread[20];

        for (int i = 0; i < 20; i++) {
            threads1[i] = new Thread(producer, "Producer-" + i);
            threads2[i] = new Thread(consumer, "Consumer-" + i);
        }

        for (int i = 0; i < 20; i++) {
            threads1[i].start();
            threads2[i].start();
        }
    }
}

查看控制檯日日誌,你會發現生產者快速加入10個數據到緩衝區,而後線程開始掛起,直到消費者開始消費數據,每次消費數據後生產者會被喚醒一次,並加入數據到緩衝區。最後20個生產者線程都執行完畢後,消費者線程才執行完畢。若是你想模擬消費者被阻塞只須要調整生產者速度慢於消費者速度。同步

Producer-0: Add one. storge size: 1.
Producer-19: Add one. storge size: 2.
Producer-18: Add one. storge size: 3.
Producer-17: Add one. storge size: 4.
Producer-16: Add one. storge size: 5.
Producer-15: Add one. storge size: 6.
Producer-14: Add one. storge size: 7.
Producer-13: Add one. storge size: 8.
Producer-12: Add one. storge size: 9.
Producer-11: Add one. storge size: 10.
Consumer-3: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9.
Producer-1: Add one. storge size: 10.
Consumer-19: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9.
Producer-10: Add one. storge size: 10.
Consumer-18: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9.
Producer-2: Add one. storge size: 10.
Consumer-17: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9.
Producer-9: Add one. storge size: 10.
Consumer-16: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9.
Producer-3: Add one. storge size: 10.
Consumer-15: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9.
Producer-8: Add one. storge size: 10.
Consumer-14: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9.
Producer-4: Add one. storge size: 10.
Consumer-13: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9.
Producer-7: Add one. storge size: 10.
Consumer-12: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9.
Producer-5: Add one. storge size: 10.
Consumer-11: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9.
Producer-6: Add one. storge size: 10.
Consumer-10: Get one Thu Nov 24 17:12:14 CST 2016. Storge size: 9.
Consumer-9: Get one Thu Nov 24 17:12:15 CST 2016. Storge size: 8.
Consumer-8: Get one Thu Nov 24 17:12:16 CST 2016. Storge size: 7.
Consumer-7: Get one Thu Nov 24 17:12:17 CST 2016. Storge size: 6.
Consumer-6: Get one Thu Nov 24 17:12:18 CST 2016. Storge size: 5.
Consumer-5: Get one Thu Nov 24 17:12:19 CST 2016. Storge size: 4.
Consumer-4: Get one Thu Nov 24 17:12:20 CST 2016. Storge size: 3.
Consumer-2: Get one Thu Nov 24 17:12:21 CST 2016. Storge size: 2.
Consumer-1: Get one Thu Nov 24 17:12:22 CST 2016. Storge size: 1.
Consumer-0: Get one Thu Nov 24 17:12:23 CST 2016. Storge size: 0.
相關文章
相關標籤/搜索