补充知识:生产者和消费者模式

声明

版权声明:本文部分内容参考自CSDN博主「一个快乐的野指针~」的原创文章,仅用作个人学习,特此声明
原文链接: https://blog.csdn.net/qq_44715943/article/details/116714584

补充知识:生产者消费者模式(wait()和notify())

1、概念

  • 生产线程负责生产,消费线程负责消费。
  • 生产线程和消费线程要达到均衡。
  • 这是一种特殊的业务需求,在这种特殊的情况下需要使用wait方法和notify方法

2、模拟一个业务需求

模拟这样一个需求:

  • 仓库我们采用List集合。
  • List集合中假设只能存储1个元素。
  • 1个元素就表示仓库了。
  • 如果List集合中元素个数是0,就表示仓库了。
  • 保证List集合中永远都是最多存储1个元素。
  • 必须做到这种效果:生产1个消费1个

3、设计思路


这种模式其实就是一种排队

因为只有生产出一个物品,才能消费;消费完这个物品,才能继续生产下一个物品。循环进行

也就是说wait方法和notify方法是建立在线程同步基础之上的,所以要考虑线程安全问题

eg.

使用wait方法和notify方法实现“生产者和消费者模式”

/**
 * object类相关方法
 * wait和notify方法测试
 * 使用wait方法和notify方法实现"生产者和消费者模式"
 * 两个线程其实是要排队的,生产完才能消费,消费完才能生产
 * 所以wait方法和notify方法是建立在synchronized线程同步的基础之上的
 */
public class ThreadTest {
    public static void main(String[] args) {
        // 创建1个仓库对象,共享的。
        List list = new ArrayList();
        // 创建两个线程对象
        // 生产者线程
        Thread t1 = new Thread(new Producer(list));
        // 消费者线程
        Thread t2 = new Thread(new Consumer(list));

        t1.setName("生产者线程");
        t2.setName("消费者线程");

        t1.start();
        t2.start();
    }
}

// 生产线程
class Producer implements Runnable {
    // 仓库
    private List list;

    public Producer(List list) {
        this.list = list;
    }
    @Override
    public void run() {
        // 一直生产(使用死循环来模拟一直生产)
        while(true){
            // 给仓库对象list加锁。
            synchronized (list){
                if(list.size() > 0){ // 大于0,说明仓库中已经有1个元素了。
                    try {
                        // 当前线程进入等待状态,并且释放Producer之前占有的list集合的锁。
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 程序能够执行到这里说明仓库是空的,可以生产
                Object obj = new Object();
                list.add(obj);
                System.out.println(Thread.currentThread().getName() + "生产物品:" + obj);
                // 唤醒消费者进行消费
                list.notifyAll();
            }
        }
    }
}

// 消费线程
class Consumer implements Runnable {
    // 仓库
    private List list;

    public Consumer(List list) {
        this.list = list;
    }

    @Override
    public void run() {
        // 一直消费
        while(true){
            synchronized (list) {
                if(list.size() == 0){
                    try {
                        // 仓库已经空了。
                        // 消费者线程等待,释放掉list集合的锁
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 程序能够执行到此处说明仓库中有数据,进行消费。
                Object obj = list.remove(0);//将集合中第0位元素移除,模拟将仓库中的唯一一个元素消费掉
                System.out.println(Thread.currentThread().getName() + "消费物品:" + obj);
                // 唤醒生产者生产。
                list.notifyAll();
            }
        }
    }
}


观察结果发现,生产者线程每生产一个物品,消费者线程就会把这个物品消费掉,消费掉之后才会继续生产,生产之后才能进行消费,达到了目的

4、知识点总结

  • 两个线程其实是要排队的,生产完才能消费,消费完才能生产

    所以wait方法和notify方法是建立在synchronized线程同步的基础之上的,需要考虑线程安全问题

  • o.wait() 方法让正在o对象上活动的线程t进入等待状态,并且释放掉t线程之前占有的o对象的锁。而o.notify() 方法会唤醒这o对象上等待的线程,只是通知,不会释放o对象上之前占有的锁。

posted @   无关风月7707  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示