【并发编程】消费者与生产者模型

生产者消费者模型

概述:

​ 生产者和消费是操作系统中一种重要的模型,它描述的是一种等待和通知的机制。

​ 在日常生活中,卖东西的商家如超市,可以看作生产者,而顾客进行购买商品则就是消费者的角色;同理,实际的软件开发过程中,经常会见到这样一幕:

​ 代码的某个模块负责生产数据(供货商),而生产出来的数据却不得不交给另一模块(消费者)来对其进行处理,在这之间我们必须要有一个类似上述超市的东西来存储数据(超市),这就抽象出了生产者/消费者模型。

其中:

生产者

产生数据的模块,就形象地称为生产者;

消费者

而处理(需要获取)数据的模块,就称为消费者;

缓冲区 (通常也叫阻塞队列)

生产者和消费者之间的中介就叫做缓冲区

image-20231030191031747

作用

​ 归根结底来说,核心作用就是解耦异步。 生产者消费者模式通过一个容器来解决生产者和消费者的强耦合问题

​ 生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

这个阻塞队列就是用来给生产者和消费者解耦和实现异步传输的。

关键点

在这个模型中,最关键就是:

  1. 内存缓冲区为空的时候消费者必须等待,
  2. 而内存缓冲区满的时候,生产者必须等待。
  3. 其他时候可以是个动态平衡。

值得注意的是多线程对临界区资源的操作时候必须保证在读写中只能存在一个线程,所以需要设计锁的策略。

多线程下的同步问题

​ 在模型中,消费者和生产者都访问缓冲区,那么肯定是多线程;消费者和生产者拿到的肯定是同一种商品,那么就要采用某种机制保护生产者和消费者之间的同步,即有生产的商品才能进行消费(与上述的异步方式要区分,异步是指生成者生产完无需等待消费者处理数据的过程,可以直接继续执行后续代码,而同步指的是对于生成和消费数据而言存在同步性机制)

​ 保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。

(即一次只能一个生产者进行生成行为,一次只能一个消费者进行消费行为)

解决方案
1. synchronized方法/代码块 中使用 wait() 与 notify()
2. BlockingQueue阻塞队列方法

​ BlockingQueue是1.5新增的内容,是一个同步队列,它在内部实现了线程同步,实现方式采用await() / signal()方法。

​ 它可以在生成对象时指定容量大小,用于阻塞操作的是put()和take()方法。
​ put()方法:类似于我们上面的生产者线程,容量达到最大时,自动阻塞。
​ take()方法:类似于我们上面的消费者线程,容量为0时,自动阻塞

3. .await() / signal()方法

​ 上面我们说过BlockingQueue底层是实现await() / signal()方法,下面我们来看一下在JDK1.5中,用ReentrantLock和Condition可以实现等待/通知模型,具有更大的灵活性。通过在Lock对象上调用newCondition()方法,将条件变量和一个锁对象进行绑定,进而控制并发程序访问竞争资源的安全

4. 信号量

Semaphore是一个计数的信号量。设置一个阈值,多个线程竞争获取信号,执行完毕后归还,当超过设定值时,线程申请许可信号被阻塞,常用来构造资源池如数据库连接池,对象池等。当阈值为1时,因只有两个状态,也叫二元信号量,可作为互斥锁使用。

文章引用

【精选】生产者消费者模型-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值