深入理解阻塞队列(一)——基本结构

BlockingQueue是一个继承自Queue的接口,在Queue的队列基础上增加了阻塞操作。简单来说,就是在在BlockingQueue为空时从队头取数据将会被阻塞,因为此时还没有数据可取,一旦队列中有数据了,取数据的线程就会释放得到了数据;如果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();
    }
  }}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

BlockingQueue类结构

BlockingQueue是阻塞队列的顶层接口,其下有很多实现类以及BlockingDeque接口(双端阻塞队列)。关系如下图: 
BlockingQueue类继承关系图 
从上图中可以看到整个BlockingQueu的结构都是在Queue的接口上扩展的,下面从Queue开始分析每个类中入队、出队、检索的方法。

Queue接口

入队 出队 检索 区别
add() remove() element() 在执行方法失败时不返回值,抛出异常
offer() poll() peek() 在执行方法时,给出返回值,比如false、null

可以看到Queue接口的三种操作:入队、出队和检索均有两个实现,区别在于其中一个会在方法执行失败时抛出异常,而另一个会在失败时返回值。下面以入队为例,add()方法在队列已满时将会抛出异常,而offer()在队列已满时会返回false。

BlockingQueue接口

BlockingQueue在Queue接口的基础上对入队和出队两个操作分别又增加了阻塞方法,如下:

阻塞入队 阻塞出队 定时入队 定时出队
put(E e) E take() offer(E e,long timeout,TimeUnit unit) E poll(long timeout,TimeUnit unit)

其中后面关于设置了时间的入队和出队操作,在时间到了之后如果还未执行成功,那么返回false和null。

Deque接口

Deque是一个双端队列,既支持在队头执行入队出队,也支持在队尾执行出队。而Queue只支持在队头出队,在队尾入队。Deque增加的接口如下:

队头入队 队头出队 队尾入队 队尾出队 队头检索 队尾检索 区别
addFirst() removeFirst() addLast() removeLast() getFirst() getLast() 在方法执行失败时会抛出异常
offerFirst() pollFirst() offerLast() pollLast() peekFirst() peekLast() 在方法执行失败时会返回false或者null

BlockingDeque接口

BlockingDeque在Deque的基础上增加了阻塞的方法,增加的方法如下:

阻塞队头入队 阻塞队头出队 阻塞队尾入队 阻塞队尾出队 区别
putFirst(E e) E takeFirst() putLast(E e) E takeLast() 没有超时设置
offerFirst(E e,long timeout,TimeUnit unit) E pollFirst(long timeout,TimeUnit unit) offerLast(E e,long timeout,TimeUnit unit) E pollLast(long timeout,TimeUnit unit) 在超时之后,返回false或者null

各个实现类

  • ArrayBlockingQueue: 一个基于数组实现的有界阻塞队列,必须设置容量
  • LinkedBlockingQueue: 基于链表实现的阻塞队列,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列
  • PriorityBlockingQueue: 一个无界的阻塞队列,使用的排序规则和PriorityQueue类似并提供了阻塞操作
  • LinkedBlockingDeque: 一个基于双端链表的双端阻塞队列,容量可以选择进行设置

总结

需要了解Queue、Deque、BlockingQueue、BlockingDeque四个接口中各个操作中各个方法的区别,比如入队,哪个方法在队列已满的情况会抛出异常,哪个方法会返回false,哪个方法又会阻塞等等。 下一篇博客将会介绍ArrayBlockingQueue,希望感兴趣的朋友继续关注。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值