【BlockingQueue阻塞队列学习】

阻塞队列的类型

1. 有限队列 bounded queue 	定义了边界也就是最大容量
2. 无限队列 unbounded queue 没有定义边界,记录无限大

BlockingQueue队列的特点

BlockingQueue不接受空元素。实现在尝试添加、放置或提供null时抛出NullPointerException。null用作标记值以指示 轮询 操作失败。
BlockingQueue可能是有容量限制的。在任何给定时间,它都可能有一个remainingCapacity,超过该容量就不能在不阻塞的情况下放置其他元素。没有任何内在容量限制的BlockingQueue始终报告Integer.MAX_VALUE的剩余容量。
BlockingQueue实现主要用于生产者-消费者队列,但还支持该Collection接口。因此,例如,可以使用 remove(x)从队列中删除任意元素。但是,此类操作通常 不会非常有效地执行,并且仅供偶尔使用,例如取消排队的消息时。
BlockingQueue实现是线程安全的。所有排队方法都使用内部锁或其他形式的并发控制以原子方式实现其效果。但是, 批量集合操作addAll、 containsAll、retainAll和removeAll不一定 以原子方式执行,除非在实现中另有说明。因此,例如, addAll(c)在仅添加c中的一些元素后可能会失败(抛出异常)。
BlockingQueue本质上不支持任何类型的“关闭”或“关闭”操作来指示不再添加任何项目。此类功能的需求和使用往往取决于实现。例如,一种常见的策略是生产者插入特殊 的流结束或有毒对象,消费者在获取时会相应地进行解释。

使用示例,基于典型的生产者-消费者场景。请注意,一个BlockingQueue可以安全地用于多个生产者和多个消费者。

使用示例

多应用与线程池, 生产消费者场景

class Producer implements Runnable {
  private final BlockingQueue queue;
  Producer(BlockingQueue q) { queue = q; }
  public void run() {
    try {
      while (true) { queue.put(produce()); }
    } catch (InterruptedException ex) { ... handle ...}
  }
  Object produce() { ... }
}

class Consumer implements Runnable {
  private final BlockingQueue queue;
  Consumer(BlockingQueue q) { queue = q; }
  public void run() {
    try {
      while (true) { consume(queue.take()); }
    } catch (InterruptedException ex) { ... handle ...}
  }
  void consume(Object x) { ... }
}

class Setup {
  void main() {
    BlockingQueue q = new SomeQueueImplementation();
    Producer p = new Producer(q);
    Consumer c1 = new Consumer(q);
    Consumer c2 = new Consumer(q);
    new Thread(p).start();
    new Thread(c1).start();
    new Thread(c2).start();
  }
}

上面是简单的一生产者两消费者的运行例子。阻塞队列即使生产者也是消费者的,构造参数也是成员变量。

队列的数据结构

FIFO是什么意思
First In First Out。先进先出, 经典的FIFO就是BlockingQueue(阻塞队列)了

1. 队列是一种存储数据的结构
2. 通常队列都是由链表或者数组来实现
3. 一般队列具备FIFO,当然也有Deque(双端队列)double-ended queue
4. 队列的主要操作主要有Enqueue(入列操作)和Dequeue(出列操作)

常见的阻塞队列类型

  • ArrayBlockingQueue 由数组支持的有界队列

  • LinkedBlockingQueue 由链接节点支持的可选有界队列

  • PriorityBlockingQueue 由优先级堆支持的无界优先级队列

  • DelayQueue 由优先级堆支持的、基于时间的调度队列

方法分析

file

阻塞队列方法的一些共同点和区别

添加类方法
add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
offer 添加一个元素并返回true 如果队列已满,则返回false
put 添加一个元素 如果队列满,则阻塞
删除类方法
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
poll 移除并返问队列头部的元素 如果队列为空,则返回null
take 移除并返回队列头部的元素 如果队列为空,则阻塞
查询类方法
element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
peek 返回队列头部的元素 如果队列为空,则返回nul

根据以上对比,在生产环境中显然大部分情况下put, take 和peek才是我们需要的,所以使用的场景会比较多. offer和poll使用超时参数的方法应用也非常广泛.

ArrayBlockingQueue

基于数组的有边界的阻塞队列

创建
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>();
工作原理

基于ReentrantLock保证线程安全,根据Condition实现队列满时的阻塞

ReentrantLock重入锁。 Reentrant重入 entrant 发音[ˈentrənt] 新员工,参赛者的意思+re前缀翻译为重入发音[ˈri:entrənt].

LinkedBlockingQueue

基于链表的无界队列(只是超大,理论上有界)

创建
BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();
//队列容量为 Integer.MAX_VALUE
1. 向LinkedBlockingQueue中插入元素永远不会阻塞
2. 使用LinkedBlockingQueue设计生产消费者模式要注意, 消费者处理速度要快于生产者的生产速度, 否则队列过长会导致内存溢出。

DelayQueue

创建
 BlockingQueue<String> blockingQueue = new DelayQueue();      
入队的对象必须要实现Delayed接口,而Delayed集成自Comparable接口
队列内部会根据时间优先级进行排序。延迟类线程池周期执行。
应用场景

电影票

BlockingQueue API

阻塞队列的方法对应主要分两大类进栈和出栈

Enqueue 入栈方法

  • add() 如果插入成功则返回 true,否则抛出 IllegalStateException 异常

  • put() 将指定的元素插入队列,如果队列满了,那么会阻塞直到有空间插入

  • offer() 如果插入成功则返回 true,否则返回 false

  • offer(E e, long timeout, TimeUnit unit)尝试将元素插入队列,如果队列已满,那么会阻塞直到有空间插入

Dequeue 出栈方法
  • take()获取队列的头部元素并将其删除,如果队列为空,则阻塞并等待元素变为可用

  • poll(long timeout, TimeUnit unit) 检索并删除队列的头部,如有必要,等待指定的等待时间以使元素可用,如果超时,则返回 null

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dangkei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值