久趣下载站

当前位置: 首页 » 游戏攻略 » 生产者-消费者模式及其应用

生产者-消费者模式及其应用

生产者-消费者模式是一个经典的多线程并发协作模式,对并发编程有着重要的意义。理解生产者-消费者问题有助于加深对并发编程的理解。

生产者-消费者模式包含两类线程:生产者线程用于生产数据,消费者线程用于消费数据。为了解耦生产者和消费者的关系,通常采用共享的数据区域,就像是一个仓库。生产者生产数据后直接放置在共享数据区中,不需要关心消费者的行为;而消费者只需要从共享数据区中获取数据,不需要关心生产者的行为。

共享数据区域应该具备以下线程间并发协作功能:

  1. 如果共享数据区已满,阻塞生产者继续生产数据;
  2. 如果共享数据区为空,阻塞消费者继续消费数据。

在实现生产者消费者问题时,可以采用三种方式:

  1. 使用BlockingQueue实现;
  2. 使用synchronized以及Object wait/notify的消息通知机制;
  3. 使用Lock Condition的await/signal消息通知机制。

BlockingQueue实现生产者-消费者:

BlockingQueue提供了可阻塞的插入和移除的方法。当队列容器已满,生产者线程会被阻塞,直到队列未满;当队列容器为空时,消费者线程会被阻塞,直至队列非空时为止。有了这个队列,生产者只需要关注生产,而不用管消费者的消费行为,更不用等待消费者线程执行完;消费者也只管消费,不用管生产者是怎么生产的,更不用等着生产者生产。

示例代码:

public class ProductorConsumer {
    // 省略部分代码
}

synchronized实现生产者-消费者:

这其实也是手动实现阻塞队列的方式。示例代码:

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.CyclicBarrier;

public class MyBlockingQueue {
    // 省略部分代码
}

Condition实现生产者-消费者:

示例代码:

public class BoundedQueue {
    // 省略部分代码
}

生产者-消费者模式的应用场景:

生产者-消费者模式一般用于将生产数据的一方和消费数据的一方分割开来,将生产数据与消费数据的过程解耦开来。

应用场景包括:

Excutor任务执行框架

通过将任务的提交和任务的执行解耦开来,提交任务的操作相当于生产者,执行任务的操作相当于消费者。

消息中间件MQ

双十一的时候,会产生大量的订单,需要将订单放入一个队列里面,然后由专门的线程处理订单。

任务的处理时间比较长的情况下

比如上传附件并处理,可以将用户上传和处理附件分成两个过程,用一个队列暂时存储用户上传的附件,然后立刻返回用户上传成功,然后有专门的线程处理队列中的附件。

生产者-消费者模式的优点:

  • 解耦:将生产者类和消费者类进行解耦,消除代码之间的依赖性,简化工作负载的管理。
  • 复用:通过将生产者类和消费者类独立开来,对生产者类和消费者类进行独立的复用与扩展。
  • 调整并发数:由于生产者和消费者的处理速度是不一样的,可以调整并发数,给予慢的一方多的并发数,来提高任务的处理速度。
  • 异步:对于生产者和消费者来说能够各司其职,生产者只需要关心缓冲区是否还有数据,不需要等待消费者处理完;对于消费者来说,也只需要关注缓冲区的内容,不需要关注生产者,通过异步的方式支持高并发。
  • 支持分布式:生产者和消费者通过队列进行通讯,所以不需要运行在同一台机器上,在分布式环境中可以通过redis的list作为队列,而消费者只需要轮询队列中是否有数据。同时还能支持集群的伸缩性,当某台机器宕掉的时候,不会导致整个集群宕掉。

关于作者:

本文已收录于作者的个人博客:
https://www.seven97.top
。公众号:seven97,欢迎关注~

猜你喜欢
本类排行