当前位置:   article > 正文

生产者-消费者中的缓冲区:BlockingQueue接口_如果生产者消费者问题中的缓冲区是无界的

如果生产者消费者问题中的缓冲区是无界的

BlockingQueue接口使用场景

相信大家对生产者-消费者模式不陌生,这个经典的多线程协作模式,最简单的描述就是生产者线程往内存缓冲区中提交任务,消费者线程从内存缓冲区里获取任务执行。在生产者-消费者模式中最重要的就是这个内存缓冲区,可能你会疑问,为什么不让生产者直接把任务提交给消费者来执行,而是要通过一个中间媒介,也就是一个缓冲区来交换任务?

  1. 通过缓冲区,可以缓解生产者和消费者之间的速度差。假设生产者的速度大于消费者,生产者不断向缓冲区内提交任务,但是缓冲区大小有限,当内存缓冲区满时,生产者不得不被阻塞,此时消费者仍不断从缓冲区内获取任务执行,直到缓冲区不为空,生产者才能继续执行。
  2. 通过缓冲区,生产者不需要知道消费者是谁,生产者只需把任务提交到缓冲区即可;同样消费者也不需要直到生产者是谁,获取任务通过缓冲区。这样做的好处在于,对于代码的维护和升级,如果我们要改动消费者,我们不需要修改生产者和缓冲区。生产者和消费者之间的通信通过缓冲区。

在生产者-消费者模式中,充当这个缓冲区使用的是BlockingQueue接口,BlockingQueue继承自Queue接口,在实例化时,可以使用ArrayBlockingQueue和LinkedBlockingQueue两种队列,前者是基于数组实现的,而后者是基于链表实现,从名字我们就可以看出。看到这两个队列大家应该有点印象,在线程池中也有这么一个参数BlockingQueue:

  1. public ThreadPoolExecutor(int corePoolSize,
  2. int maximumPoolSize,
  3. long keepAliveTime,
  4. TimeUnit unit,
  5. BlockingQueue<Runnable> workQueue,
  6. ThreadFactory threadFactory,
  7. RejectedExecutionHandler handler)
  8. /*
  9. *corePoolSize:线程池中的线程数量.
  10. *maximumPoolSize:线程池中的最大线程数.
  11. *keepAliveTime:当线程池中线程数量超过corePoolSize时,多余的空闲线程的存活时间.
  12. *unit:keepAliveTime的单位.
  13. *workQueue:任务队列,被提交进线程池,但没被执行的任务.
  14. *threadFactory:线程工厂,用于创建线程,可自定义线程.
  15. *handler:拒绝服务,当线程池中没有空闲线程为新任务服务时,且等待队列中也已经满时,执行的策略.
  16. */

线程池中的workQueue任务等待队列用来保存被提交进线程池,但因为没有空闲线程,所以尚未被执行的任务。使用ArrayBlockingQueue做为有界队列,LinkedBlockingQueue做为无界队列,无界队列因为基于链表实现,所以不会出现任务入队列失败的情况,直到内存耗尽为止。

为什么使用BlockingQueue做为内存缓冲区

用回生产者-消费者模式举例说,在多线程环境下,当生产者线程向内存缓冲区提交了一个任务后,消费者线程怎么知道此时内存缓冲区内有新的任务提交?如果我们让消费者线程不断查询缓冲区内的任务提交情况,是可以,不过这样不是一个效率高的方法。

在线程池中也是,使用BlockingQueue队列,关键是Blocking,假设我们使用的是ArrayBlockingQueue,基于数组实现的有界队列,生产者线程不断向任务队列(也就是缓冲区)内提交任务时,当任务队列已经放满待执行任务后,生产者线程就会被阻塞,直到缓冲区内有空闲位置后,才会唤醒生产者线程。当消费者线程不断从缓冲区内获取任务执行时,假设所有任务都被获取后,消费者线程也会被阻塞,直到缓冲区内有新的任务被提交,消费者线程被重新唤醒。这是怎么做到的?使用BlockingQueue队列的线程是怎么如何在队列满时,让提交任务线程阻塞,而在队列为空,如何让获取任务线程阻塞?来看看BlockingQueue的内部实现。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/267920
推荐阅读
相关标签
  

闽ICP备14008679号