1. 程式人生 > >wait、notify應用場景(生產者-消費者模式)

wait、notify應用場景(生產者-消費者模式)

Java實現生產者消費者的方式有:wait && notify、BlockingQueue、Lock && Condition等

wait、notify注意事項:
(1)可以使用wait()和notify()方法在Java中實現執行緒間通訊。不只是一個或兩個執行緒,而是多個執行緒可以使用這些方法相互通訊。
(2)在synchronized方法或synchronized塊中呼叫wait(),notify()和notifyAll()方法,否則JVM將丟擲IllegalMonitorStateException。
(3)從while(條件)迴圈呼叫wait和notify方法,而不是從if()塊呼叫,因為要重複檢查條件,而不僅僅是一次。
(4)多使用notifyAll方法而不是notify。


下面是wait、notify等待通知實現的生產者-消費者模式:
生產者:

/**
 * 生產者
 *
 * @author tangquanbin
 * @date 2018/12/15 11:13
 */
public class Producer implements Runnable {
    /**
     * 產品容器
     */
    private final List<Integer> container;

    public Producer(List<Integer> container) {
        this.container = container;
    }

    /**
     * 生產者生產方法
     *
     * @throws InterruptedException
     */
    private void produce() throws InterruptedException {
        //產品容器容量
        int capacity = 5;
        synchronized (container) {
            //當容器已滿,暫停生產
            while (container.size() == capacity) {
                System.out.println("...容器已經滿了,暫停生產...");
                container.wait();
            }
            Random random = new Random();
            int p = random.nextInt(50);
            //模擬1秒生產一個產品
            TimeUnit.MILLISECONDS.sleep(1000);
            System.out.println("生產產品:" + p);
            container.add(p);
            container.notifyAll();
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                produce();
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("produce error");
            }
        }
    }
}

  消費者:

/**
 * 消費者
 * @author tangquanbin
 * @date 2018/12/15 11:13
 */
public class Consumer implements Runnable{

    /**
     * 產品容器
     */
    private final List<Integer> container;

    public Consumer(List<Integer> container) {
        this.container = container;
    }

    /**
     * 消費者消費產品
     */
    private void consume() throws InterruptedException {
        synchronized (container){
            while (container.isEmpty()){
                System.out.println("...容器是空的,暫停消費...");
                container.wait();
            }
            Integer p = container.remove(0);
            //模擬1秒消費一個產品
            TimeUnit.MILLISECONDS.sleep(1000);
            System.out.println("消費產品:" + p);
            container.notifyAll();
        }
    }
    @Override
    public void run() {
        while (true){
            try {
                consume();
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("consume error");
            }
        }
    }
}

  測試:

public class ProducerConsumerTest {
    public static void main(String[] args) {
        List<Integer> container = new ArrayList<>();
        Thread producer = new Thread(new Producer(container));
        Thread consumer = new Thread(new Consumer(container));
        producer.start();
        consumer.start();
    }
}

  輸出:

生產產品:14
生產產品:17
消費產品:14
生產產品:0
生產產品:39
生產產品:4
生產產品:3
...容器已經滿了,暫停生產...
消費產品:17
消費產品:0
消費產品:39
消費產品:4
消費產品:3
...容器是空的,暫停消費...
生產產品:25
生產產品:33
生產產品:17
消費產品:25
消費產品:33
消費產品:17
...容器是空的,暫停消費...