Java BlockingQueue阻塞队列

Posted hequnwang10

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java BlockingQueue阻塞队列相关的知识,希望对你有一定的参考价值。

一、定义

BlockingQueue其实就是阻塞队列,是基于阻塞机制实现的线程安全的队列。而阻塞机制的实现是通过在入队和出队时加锁的方式避免并发操作。

BlockingQueue不同于普通的Queue的区别主要是:

  1. 通过在入队和出队时进行加锁,保证了队列线程安全
  2. 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。

BlockingQueue常用于生产者-消费者模型中,往队列里添加元素的是生产者,从队列中获取元素的是消费者;通常情况下生产者和消费者都是由多个线程组成。

二、BlockingQueue 的方法

public interface BlockingQueue<E> extends Queue<E> 
    /**
     * 入队一个元素,如果有空间则直接插入,并返回true;
     * 如果没有空间则抛出IllegalStateException
     */
    boolean add(E e);

    /**
     * 入队一个元素,如果有空间则直接插入,并返回true;
     * 如果没有空间返回false
     */
    boolean offer(E e);

    /**
     * 入队一个元素,如果有空间则直接插入,如果没有空间则一直阻塞等待
     */
    void put(E e) throws InterruptedException;

    /**
     * 入队一个元素,如果有空间则直接插入,并返回true;
     * 如果没有空间则等待timeout时间,插入失败则返回false
     */
    boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;

    /**
     * 出队一个元素,如果存在则直接出队,如果没有空间则一直阻塞等待
     */
    E take() throws InterruptedException;

    /**
     * 出队一个元素,如果存在则直接出队,如果没有空间则等待timeout时间,无元素则返回null
     */
    E poll(long timeout, TimeUnit unit) throws InterruptedException;

    /**
     * 返回该队列剩余的容量(如果没有限制则返回Integer.MAX_VALUE)
     */
    int remainingCapacity();

    /**
     * 如果元素o在队列中存在,则从队列中删除
     */
    boolean remove(Object o);

    /**
     * 判断队列中是否存在元素o
     */
    public boolean contains(Object o);

    /**
     * 将队列中的所有元素出队,并添加到给定的集合c中,返回出队的元素数量
     */
    int drainTo(Collection<? super E> c);

    /**
     * 将队列中的元素出队,限制数量maxElements个,并添加到给定的集合c中,返回出队的元素数量
     */
    int drainTo(Collection<? super E> c, int maxElements);


BlockingQueue 具有 4 组不同的方法用于插入、移除以及对队列中的元素进行检查。如果请求的操作不能得到立即执行的话,每个方法的表现也不同。这些方法如下:

  • 抛异常: 如果试图的操作无法立即执行,抛一个异常。
  • 特定值: 如果试图的操作无法立即执行,返回一个特定的值(常常是 true / false)。
  • 阻塞: 如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。
  • 超时: 如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。返回一个特定值以告知该操作是否成功(典型的是 true / false)。

无法向一个 BlockingQueue 中插入 null。如果你试图插入 null,BlockingQueue 将会抛出一个 NullPointerException。
可以访问到 BlockingQueue 中的所有元素,而不仅仅是开始和结束的元素。比如说,你将一个对象放入队列之中以等待处理,但你的应用想要将其取消掉。那么你可以调用诸如 remove(o) 方法来将队列之中的特定对象进行移除。但是这么干效率并不高(译者注: 基于队列的数据结构,获取除开始或结束位置的其他对象的效率不会太高),因此你尽量不要用这一类的方法,除非你确实不得不那么做。

三、BlockingQueue实现类及原理

主要实现类


其中在日常开发中用的比较多的是ArrayBlockingQueueLinkedBlockingQueue,本文也将主要介绍这两个实现类的原理。

1、ArrayBlockingQueue的用法和原理

ArrayBlockingQueue是基于数组实现的阻塞队列。
是一个有界的阻塞队列,其内部实现是将对象放到一个数组里。有界也就意味着,它不能够存储无限多数量的元素。它有一个同一时间能够存储元素数量的上限。你可以在对其初始化的时候设定这个上限,但之后就无法对这个上限进行修改了(译者注: 因为它是基于数组实现的,也就具有数组的特性: 一旦初始化,大小就无法修改)。
ArrayBlockingQueue 内部以 FIFO(先进先出)的顺序对元素进行存储。队列中的头元素在所有元素之中是放入时间最久的那个,而尾元素则是最短的那个。

以上是关于Java BlockingQueue阻塞队列的主要内容,如果未能解决你的问题,请参考以下文章

Java BlockingQueue阻塞队列

Java数据结构及算法实战系列008:Java队列02——阻塞队列BlockingQueue

Java数据结构及算法实战系列008:Java队列02——阻塞队列BlockingQueue

Java阻塞队列BlockingQueue(生产者消费者模型)

Java阻塞队列BlockingQueue(生产者消费者模型)

阻塞队列(BlockingQueue)