Java 中的 BlockingQueue

2024年9月10日 | 11 分钟阅读

在直接深入“阻塞队列”主题之前,让我们先简要了解一下队列。队列是一个有序的对象列表,插入发生在列表的末尾,而删除发生在列表的开头。因此,也说队列是基于 FIFO(先进先出)原则的。

阻塞队列是一种额外支持操作的队列,当尝试检索元素时,它会等待队列非空,当要将元素插入队列时,它会等待队列变为空。Java 1.5 提供了对 BlockingQueue 接口以及其他并发实用类别的支持。

关于阻塞队列的一些要点:

  • 阻塞队列可能有一个剩余容量,超过该容量,在不阻塞的情况下将无法插入任何元素。
  • 与阻塞队列相关的所有实现都是线程安全的。所有方法都通过内部锁或其他形式的并发控制来实现其事件。
  • 阻塞队列不允许包含 null 元素。如果尝试添加 null 值,实现将抛出 NullPointerException。
  • Java 5 在 java.util.concurrent 包中提供了 BlockingQueue 的实现。

BlockingQueue 实现类

由于 BlockingQueue 是一个接口,因此无法直接提供 BlockingQueue 的实例,要实现 BlockingQueue,我们需要创建实现它的类。

  1. ArrayBlockingQueue
  2. DelayQueue
  3. LinkedBlockingDeque
  4. LinkedBlockingQueue
  5. LinkedTransferQueue
  6. PriorityBlockingQueue
  7. SynchronousQueue

LinkedBlockingQueue 和 ArrayBlockingQueue 是用于实现 BlockingDeque 类的类。这两个类分别是 BlockingDeque 和链表数据结构的组合,以及 BlockingDeque 和数组的组合。

使用 BlockingQueue 的语法

我们使用 import 语句来使用上述类,并导入 java.util.concurrent.BlockingQueue 包。

声明一个 BlockingQueue

使用 LinkedBlockingDeque 创建 BlockingQueue 类的对象

使用 ArrayBlockingQueue 创建 BlockingQueue 类的对象

BlockingQueue 接口的方法

在 BlockingQueue 的实现中有三类方法:

1. 抛出异常的方法

  1. add( ):它将一个元素插入到 BlockingQueue 的队列末尾。当队列已满时,它会抛出异常。
  2. element( ):它返回队列的顶部或头部。如果队列为空,它会抛出异常。
  3. remove( ):它从 BlockingQueue 中删除一个元素。如果队列为空,它会抛出异常。

2. 返回某些值的方法

i. offer( ):它将指定的元素插入到 BlockingQueue 的队列末尾。如果队列已满,则返回 false。该方法还可以与超时一起使用,即可以将时间单位作为参数传递。

例如

此处,value 是要插入到队列中的元素。上述方法将尝试将元素插入 BlockingQueue 100 毫秒。如果元素在 100 毫秒内无法插入,则方法返回 false。

peek( ):它返回 BlockingQueue 的顶部或头部。如果队列为空,则返回 null。

poll( ):它从 BlockingQueue 中删除一个元素。如果队列为空,则返回 null。它也可以与超时一起使用,即可以将时间单位作为参数传递。

3. 阻塞操作的方法

  1. put( ):该方法将一个元素插入到 BlockingQueue。如果队列已满,put() 方法将等待直到队列有足够的可用空间来插入元素。
  2. take( ):该方法从 BlockingQueue 中删除并返回一个元素。如果队列为空,take() 方法将等待直到队列中有元素可供删除。

BlockingQueue 类型

阻塞队列有两种类型:

1. 无界队列:无界阻塞队列是永不阻塞的队列,因为它的尺寸可以增长到非常大的尺寸。BlockingQueue 的容量将被设置为 Integer.MAX_VALUE。当添加元素时,无界队列的尺寸会增长。

语法

2. 有界队列:另一种类型的阻塞队列是有界队列。可以通过将队列的容量传递给队列的构造函数来创建它。

语法

示例

让我们看一个解释阻塞队列概念的例子。

输出

Content of BLockingQueue : [ A ,  B ,  C ,  D ,  E ,  F ,  G ]
The number removed is :  A 
Content of BLockingQueue after deleting one element : [ B ,  C ,  D ,  E ,  F ,  G ]    

基本操作

让我们更广泛地了解可以在阻塞队列上执行的不同操作:

  1. 添加元素
  2. 访问元素
  3. 删除元素
  4. 遍历元素

1. 添加元素

我们可以以不同的方式将元素添加到“LinkedBlockedDeque”中,具体取决于我们试图将其用作的结构类型。将元素添加到双端队列末尾的最常用方法是“add()”方法。还有一个名为“addAll()”的函数,用于将整个元素集合添加到 LinkedBlockingDeque。为了使用双端队列作为队列,可以在程序中使用“add()”和“put()”等函数。

示例

输出

 Contents of Blocking Queue : [ A ,  B ,  C ,  D ,  E ]
 Contents of another Blocking Queue : [ A ,  B ,  C ,  D ,  E ]    

2. 访问元素

我们可以使用 contains()、element()、peek()、poll() 等方法来访问“LinkedBlockingDeque”的元素。

示例

输出

The contents of the Linked Blocking Queue is : 
   [ A ,  B ,  C ,  D ,  E ]
   Yayy! Element C successfully founded in the queue 
   The top element of the queue is :  A   

3. 删除元素

可以使用 remove() 从 LinkedBlockingDeque 中删除元素。take() 和 poll() 等方法也可以用于删除第一个和最后一个元素。

示例

输出

The content of LinkedBlockingDeque is : 
    [ A ,  B ,  C ,  D ,  E ]
    The content of the LinkedBlockingDeque after removing elements is : 
    [ A ,  B ,  D ]  

4. 遍历元素

为了遍历“LinkedBlockingDeque”的元素,我们可以创建一个迭代器,并使用 Iterable 接口的方法(它是 Java Collection Framework 的根)来访问元素。Iterable 的“next()”方法返回任何集合的元素。

输出

The content of the Linked Blocking Deque is : 
 A   B   C   D   E      

BlockingQueue 方法

方法描述
boolean add( E e )如果可能立即将指定元素插入指定队列而不会违反容量限制,则返回 true,如果当前没有可用空间,则抛出 IllegalStateException。
boolean contains( Object o )如果此队列包含指定的元素,则返回 true。
int drainTo( Collection< ? super E > c )从该队列中删除所有可用元素,并将它们添加到给定的集合中。
int drainTo( Collection< ? super E > c, int maxElements )从该队列中删除最多给定数量的可用元素,并将它们添加到给定的集合中。
boolean offer( E e )如果可能立即将指定元素插入此队列而不会违反容量限制,则返回 true,如果当前没有可用空间,则返回 false。
boolean offer( E e, long timeout, TimeUnit unit )将指定元素插入此队列,必要时等待最长指定的等待时间,以使空间可用。
E poll( long timeout, TimeUnit unit )检索并删除此队列的头部,必要时等待最长指定的等待时间,以使元素可用。
void put( E e )将指定元素插入此队列,必要时等待,直到空间可用。
int remainingCapacity( )返回此队列在理想情况下(在没有内存或资源限制的情况下)可以接受而不会阻塞的额外元素的数量,如果没有内在限制,则返回 Integer.MAX_VALUE。
boolean remove( Object o )如果指定元素存在,则从此队列中删除该元素的单个实例。
E take( )检索并删除此队列的头部,必要时等待,直到元素可用。

BlockingQueue 方法的行为

BlockingQueue 提供了一些用于对阻塞队列执行插入、删除和检查操作的方法。如果请求的操作未立即满足,四组方法中的每一组都具有不同的行为。

  1. 抛出异常:如果请求的操作未立即满足,将抛出异常。
  2. 特殊值:如果操作未立即满足,将返回一个特殊值。
  3. 阻塞:如果尝试的操作未立即满足,则方法调用将被阻塞,并等待其执行。
  4. 超时:返回特殊值以确定操作是否成功。如果请求的操作未立即发生,则方法调用将阻塞直到其发生,但等待时间不超过指定时间。