模拟wait与notifyAll实现简单的生产者消费者模式 | Eddie'Blog
模拟wait与notifyAll实现简单的生产者消费者模式

模拟wait与notifyAll实现简单的生产者消费者模式

eddie 308 2021-04-19

目录

代码片段

一、产品实体类(代码:产品经理)

 * @author eddie.lee
 * @ClassName Product
 * @description 产品POJO类
 * @modified by
 */
public class Product {

    /**
     * 产品id
     */
    private Integer id;

    public Product(Integer id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                '}';
    }
}

二、存储产品类 (代号:公司)

/**
 * @author eddie.lee
 * @ClassName Storage
 * @description 存储产品
 * @modified by
 */
public class Storage {

    /**
     * 存放产品的集合
     */
    //private final LinkedList<Product> list = new LinkedList<>();
    private List<Product> list = new ArrayList<>();

    /**
     * 从仓库中获取产品来消费
     *
     */
    public synchronized void pop() {
        // 如果仓库已经消费空了,那么您就等待新品上市~
        if (list.isEmpty()) {
            System.out.println("仓库已经清空,等待下一批生成");
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 通知生产
        notifyAll();
        // 仓库没空,从仓库中拿出一个产品
        Product product = list.get(0);
        list.remove(product);
        System.out.println("    --> 产品出库:" + product);
    }

    /**
     * 将生产者生产的产品入库
     *
     * @param producedProduct
     */
    public synchronized void push(Product producedProduct) {
        // 如果当前仓库已经满了
        int maxSize = 5;
        if (list.size() >= maxSize) {
            System.out.println("仓库已经满啦,没地方放了,快停止生产吧,通知消费者来消费");
            try {
                wait();// 停止生产
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 通知消费
        notifyAll();
        // 仓库未满,既然生产了就入库吧
        list.add(producedProduct);
        System.out.println(" <-- 产品入库:" + producedProduct);
    }

}

三、生产者(代号:程序员)

/**
 * @author eddie.lee
 * @ClassName Producer
 * @description 生产者-负责生产产品
 * @modified by
 */
public class Producer implements Runnable {

    private Storage storage;

    public Producer(Storage storage) {
        this.storage = storage;
    }

    @Override
    public void run() {
        int num = 10;
        for (int i = 0; i < num; i++) {
            Product product = new Product(i);
            storage.push(product);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

三、消费者(代号:销售)

/**
 * @author eddie.lee
 * @ClassName Consumer
 * @description 消费者-消费产品
 * @modified by
 */
public class Consumer implements Runnable {

    private Storage storage;

    public Consumer(Storage storage) {
        this.storage = storage;
    }

    @Override
    public void run() {
        int num = 10;
        for (int i = 0; i < num; i++) {
            storage.pop();
            try {
                // 消费睡眠时间慢过生产时间,不明显,
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

四、入口(代号:客户)

/**
 * @author eddie.lee
 * @ClassName Controller
 * @description
 * @modified by
 */
public class Controller {

    public static void main(String[] args) {
        Storage storage = new Storage();
        Producer producer = new Producer(storage);
        Consumer consumer = new Consumer(storage);
        new Thread(producer).start();
        new Thread(consumer).start();
    }

}

五、打印日志(代号:流水清单)

仓库已经清空,等待下一批生成
 <-- 产品入库:Product{id=0}
    --> 产品出库:Product{id=0}
 <-- 产品入库:Product{id=1}
    --> 产品出库:Product{id=1}
仓库已经清空,等待下一批生成
 <-- 产品入库:Product{id=2}
    --> 产品出库:Product{id=2}
仓库已经清空,等待下一批生成
 <-- 产品入库:Product{id=3}
    --> 产品出库:Product{id=3}
仓库已经清空,等待下一批生成
 <-- 产品入库:Product{id=4}
    --> 产品出库:Product{id=4}
 <-- 产品入库:Product{id=5}
    --> 产品出库:Product{id=5}
仓库已经清空,等待下一批生成
 <-- 产品入库:Product{id=6}
    --> 产品出库:Product{id=6}
仓库已经清空,等待下一批生成
 <-- 产品入库:Product{id=7}
    --> 产品出库:Product{id=7}
仓库已经清空,等待下一批生成
 <-- 产品入库:Product{id=8}
    --> 产品出库:Product{id=8}
仓库已经清空,等待下一批生成
 <-- 产品入库:Product{id=9}
    --> 产品出库:Product{id=9}

说明

  1. wait()使用必需在synchronized包括内,wait()会让synchronized的线程暂时停止运行,释放锁并且失去控制权。
  2. notifyAll()来唤醒正在wait的线程,让任务继续往下走
  3. 生产者与消费者共用一个Storage里面的集合
  4. 仓库集合空了,消费者就会调用wait()方法暂停线程,让生产者notifyAll唤醒线程,直到仓库满载情况下,进入wait(),让消费者再次notifyAll唤醒线程去消费。

# Java