Java多线程 BlockingQueue实现生产者消费者模型详解

 更新时间:2019年09月06日 08:59:39   作者:Rest探路者  
这篇文章主要介绍了Java多线程 BlockingQueue实现生产者消费者模型详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

BlockingQueue

BlockingQueue、解决了多线程中,如何高效安全“传输”数据的问题。程序员无需关心什么时候阻塞线程,什么时候唤醒线程,该唤醒哪个线程。

方法介绍

BlockingQueue是Queue的子类

void put(E e)

插入指定元素,当BlockingQueue为满,则线程阻塞,进入Waiting状态,直到BlockingQueue有空闲空间再继续。
这里以ArrayBlockingQueue为例进行分析

void take()

队首出队,当BlockingQueue为空,则线程阻塞,进入Waiting状态,直到BlockingQueue不为空再继续。

int drainTo(Collection<? super E> c)

从队列中批量取出数据,并放入到另一个集合中,返回转移数据的数量,只需一次加锁和解锁。

BlockingQueue的实现类

ArrayBlockingQueue

  /*
   * Concurrency control uses the classic two-condition algorithm
   * found in any textbook.
   */

  /** Main lock guarding all access */
  final ReentrantLock lock;

  /** Condition for waiting takes */
  private final Condition notEmpty;

  /** Condition for waiting puts */
  private final Condition notFull;

基于数组实现的BlockingQueue,需要指定队列容量,可以指定是否为公平锁;只有一个ReentrantLock,生产者和消费者不能异步执行。

LinkedBlockingQueue

  /** Lock held by take, poll, etc */
  private final ReentrantLock takeLock = new ReentrantLock();

  /** Wait queue for waiting takes */
  private final Condition notEmpty = takeLock.newCondition();

  /** Lock held by put, offer, etc */
  private final ReentrantLock putLock = new ReentrantLock();

  /** Wait queue for waiting puts */
  private final Condition notFull = putLock.newCondition();

基于链表实现的BlockingQueue,可以指定队列容量,不指定队列容量默认为Integer.MAX_VALUE;有两个ReentrantLock,生产者和消费者可以异步执行。

BlockingQueue实现生产者消费者模型

缓冲区可以存放大量数据

生产者和消费者速度各不相同

public class MyThread42 {
  public static void main(String[] args)
  {
    final BlockingQueue<String> bq = new ArrayBlockingQueue<String>(10);
    Runnable producerRunnable = new Runnable()
    {
      int i = 0;
      public void run()
      {
        while (true)
        {
          try
          {
            System.out.println("我生产了一个" + i++);
            bq.put(i + "");
            Thread.sleep(1000);
          }
          catch (InterruptedException e)
          {
            e.printStackTrace();
          }
        }
      }
    };
    Runnable customerRunnable = new Runnable()
    {
      public void run()
      {
        while (true)
        {
          try
          {
            System.out.println("我消费了一个" + bq.take());
            Thread.sleep(3000);
          }
          catch (InterruptedException e)
          {
            e.printStackTrace();
          }
        }
      }
    };
    Thread producerThread = new Thread(producerRunnable);
    Thread customerThread = new Thread(customerRunnable);
    producerThread.start();
    customerThread.start();
  }
}

输出结果如下

我生产了一个0
我消费了一个1
我生产了一个1
我生产了一个2
我消费了一个2
我生产了一个3
我生产了一个4
我生产了一个5
我消费了一个3
我生产了一个6
我生产了一个7
我生产了一个8
我消费了一个4
我生产了一个9
我生产了一个10
我生产了一个11
我消费了一个5
我生产了一个12
我生产了一个13
我生产了一个14
我消费了一个6
我生产了一个15
我生产了一个16
我消费了一个7
我生产了一个17
我消费了一个8
我生产了一个18
我消费了一个9
我生产了一个19
我消费了一个10
我生产了一个20
我消费了一个11
我生产了一个21
我消费了一个12
我生产了一个22
我消费了一个13
我生产了一个23
我消费了一个14
我生产了一个24

······

生产者没有生产到BlockingQueue的容量(极限是10)之前,生产3个,消费1个,再生产到BlockingQueue的容量之后,生产一个消费一个,因为不能超过BlockingQueue的容量。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • idea构建web项目的超级详细教程

    idea构建web项目的超级详细教程

    好多朋友在使用IDEA创建项目时,总会碰到一些小问题,下面这篇文章主要给大家介绍了关于idea构建web项目的超级详细教程,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-03-03
  • Spring boot实现上传文件到本地服务器

    Spring boot实现上传文件到本地服务器

    这篇文章主要为大家详细介绍了Spring boot实现上传文件到本地服务器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • Java8 实现stream将对象集合list中抽取属性集合转化为map或list

    Java8 实现stream将对象集合list中抽取属性集合转化为map或list

    这篇文章主要介绍了Java8 实现stream将对象集合list中抽取属性集合转化为map或list的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • java 实现汉诺塔详解及实现代码

    java 实现汉诺塔详解及实现代码

    这篇文章主要介绍了java 实现汉诺塔详解及实现代码的相关资料,需要的朋友可以参考下
    2017-04-04
  • java理论基础Stream管道流状态与并行操作

    java理论基础Stream管道流状态与并行操作

    这篇文章主要为大家介绍了java理论基础Stream管道流状态与并行操作,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • Java使用EasyExcel动态添加自增序号列

    Java使用EasyExcel动态添加自增序号列

    本文将介绍如何通过使用EasyExcel自定义拦截器实现在最终的Excel文件中新增一列自增的序号列,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Spring注解@Qualifier的详细用法你知道几种

    Spring注解@Qualifier的详细用法你知道几种

    本文给大家分享Spring注解@Qualifier的详细用法,包括@Autowired和@Resource区别介绍,本文通过示例代码给大家详细介绍,感兴趣的朋友跟随小编一起看看吧
    2021-07-07
  • 一文掌握Xposed和LSPosed框架

    一文掌握Xposed和LSPosed框架

    Xposed和LSPosed都是用于Android系统的模块化框架,允许用户通过加载模块来修改应用程序或系统行为,LSPosed是基于Xposed的现代化实现,感兴趣的朋友跟随小编一起看看吧
    2025-01-01
  • 如何处理器拦截器(HandlerInterceptor)

    如何处理器拦截器(HandlerInterceptor)

    这篇文章主要介绍了如何处理器拦截器(HandlerInterceptor)问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • 如何使用Mockito调用静态方法和void方法

    如何使用Mockito调用静态方法和void方法

    这篇文章主要介绍了如何使用Mockito调用静态方法和void方法的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07

最新评论