当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Java BlockingQueue用法及代码示例


BlockingQueue接口Java 中的 与各种其他并发实用程序类一起添加到 Java 1.5 中,例如ConcurrentHashMap,计数信号量,CopyOnWriteArrrayLisBlockingQueue 接口通过在 BlockingQueue 已满或为空时引入阻塞来支持流量控制(除了队列之外)。尝试将元素加入已满队列的线程会被阻塞,直到其他线程通过使一个或多个元素出列或完全清除队列来在队列中腾出空间。类似地,它会阻塞尝试从空队列中删除的线程,直到其他线程插入项目为止。 BlockingQueue 不接受空值。如果我们尝试将空项放入队列,则会抛出异常NullPointerException.
Java 提供了多种 BlockingQueue 实现,例如LinkedBlockingQueue,ArrayBlockingQueue,PriorityBlockingQueue,SynchronousQueue等。Java BlockingQueue 接口实现是线程安全的。 BlockingQueue 的所有方法本质上都是原子的,并使用内部锁或其他形式的并发控制。 Java 5 附带了 BlockingQueue 实现java.util.concurrent包

BlockingQueue的用法

Usage of BlockingQueue 

由生产者 (put) 线程和消费者 (take) 线程访问的 BlockingQueue

BlockingQueue的层次结构

Hierarchy of BlockingQueue

声明

public interface BlockingQueue<E> extends Queue<E>

这里,E是Collection中存储的元素的类型。

实现 BlockingQueue 的类

我们无法直接提供 BlockingQueue 的实例,因为它是一个接口,因此要利用 BlockingQueue 的函数,我们需要使用实现它的类。另外,要在代码中使用 BlockingQueue,请使用此 import 语句。

import java.util.concurrent.BlockingQueue;
                    (or)
import java.util.concurrent.*;

BlockingDeque的实现类是LinkedBlockingDeque。该类是BlockingDeque和链表数据结构的实现。 LinkedBlockingDeque 可以选择使用构造函数进行限制,但是,如果未指定容量,则默认情况下它是 Integer.MAX_VALUE。节点在插入时动态添加,遵守容量限制。

创建对象的语法:

BlockingQueue<?> objectName = new LinkedBlockingDeque<?>();   
                         (or)
LinkedBlockingDeque<?> objectName = new LinkedBlockingDeque<?>();

示例:在下面给出的代码中,我们对 LinkedBlockingDeque 执行一些基本操作,例如创建对象、添加元素、删除元素以及使用迭代器遍历 LinkedBlockingDeque。

BlockingQueue Types

BlockingQueue 有两种类型:

1.无界队列:阻塞队列的容量将设置为Integer.MAX_VALUE。在无界阻塞队列的情况下,队列永远不会阻塞,因为它可能会增长到非常大的大小。当你添加元素时,它的大小会增加。

用法:

BlockingQueue blockingQueue = new LinkedBlockingDeque();

2.有界队列:第二种队列是有界队列。对于有界队列,您可以创建一个在队列构造函数中传递队列容量的队列:

用法:

// Creates a Blocking Queue with capacity 5
BlockingQueue blockingQueue = new LinkedBlockingDeque(5);

使用 BlockingQueue 实现有界信号量

Java


// Java program that explains the internal
// implementation of BlockingQueue
import java.io.*;
import java.util.*;
class BlockingQueue<E> {
    // BlockingQueue using LinkedList structure
    // with a constraint on capacity
    private List<E> queue = new LinkedList<E>();
    // limit variable to define capacity
    private int limit = 10;
    // constructor of BlockingQueue
    public BlockingQueue(int limit) { this.limit = limit; }
    // enqueue method that throws Exception
    // when you try to insert after the limit
    public synchronized void enqueue(E item)
        throws InterruptedException
    {
        while (this.queue.size() == this.limit) {
            wait();
        }
        if (this.queue.size() == 0) {
            notifyAll();
        }
        this.queue.add(item);
    }
    // dequeue methods that throws Exception
    // when you try to remove element from an
    // empty queue
    public synchronized E dequeue()
        throws InterruptedException
    {
        while (this.queue.size() == 0) {
            wait();
        }
        if (this.queue.size() == this.limit) {
            notifyAll();
        }
        return this.queue.remove(0);
    }
   
    public static void main(String []args)
    {
    }
}



例子:

Java


// Java Program to demonstrate usage of BlockingQueue
import java.util.concurrent.*;
import java.util.*;
public class GFG {
    public static void main(String[] args)
        throws InterruptedException
    {
        // define capacity of ArrayBlockingQueue
        int capacity = 5;
        // create object of ArrayBlockingQueue
        BlockingQueue<String> queue
            = new ArrayBlockingQueue<String>(capacity);
        // Add elements to ArrayBlockingQueue using put
        // method
        queue.put("StarWars");
        queue.put("SuperMan");
        queue.put("Flash");
        queue.put("BatMan");
        queue.put("Avengers");
        // print Queue
        System.out.println("queue contains " + queue);
        // remove some elements
        queue.remove();
        queue.remove();
        // Add elements to ArrayBlockingQueue
        // using put method
        queue.put("CaptainAmerica");
        queue.put("Thor");
        System.out.println("queue contains " + queue);
    }
}
输出:
queue contains [StarWars, SuperMan, Flash, BatMan, Avengers]
queue contains [Flash, BatMan, Avengers, CaptainAmerica, Thor]

Basic Operations

1. 添加元素

根据我们尝试使用的结构类型,可以以不同的方式将元素添加到 LinkedBlockedDeque 中。最常见的方法是add()方法,使用它我们可以在双端队列的末尾添加元素。我们还可以使用addAll()方法(这是Collection接口的一个方法)将整个集合添加到LinkedBlockingDeque中。如果我们希望将双端队列用作队列,我们可以使用add()和put()。

Java


// Java Program Demonstrate add()
// method of BlockingQueue
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.*;
public class GFG {
   
    public static void main(String[] args)
        throws IllegalStateException
    {
        // create object of BlockingQueue
        BlockingQueue<Integer> BQ
            = new LinkedBlockingDeque<Integer>();
        // Add numbers to the BlockingQueue
        BQ.add(7855642);
        BQ.add(35658786);
        BQ.add(5278367);
        BQ.add(74381793);
        // before removing print BlockingQueue
        System.out.println("Blocking Queue: " + BQ);
    }
}
输出
Blocking Queue: [7855642, 35658786, 5278367, 74381793]

2. 访问元素

可以使用contains()、element()、peek()、poll() 访问LinkedBlockingDeque 的元素。这些方法也有多种变体,上表中给出了它们及其说明。

Java


// Java Program for Accessing the elements of a
// LinkedBlockingDeque
import java.util.concurrent.*;
public class AccessingElements {
    public static void main(String[] args)
    {
        // Instantiate an object of LinkedBlockingDeque
        // named lbdq
        BlockingQueue<Integer> lbdq
            = new LinkedBlockingDeque<Integer>();
        // Add elements using add()
        lbdq.add(22);
        lbdq.add(125);
        lbdq.add(723);
        lbdq.add(172);
        lbdq.add(100);
        // Print the elements of lbdq on the console
        System.out.println(
            "The LinkedBlockingDeque, lbdq contains:");
        System.out.println(lbdq);
        // To check if the deque contains 22
        if (lbdq.contains(22))
            System.out.println(
                "The LinkedBlockingDeque, lbdq contains 22");
        else
            System.out.println("No such element exists");
        // Using element() to retrieve the head of the deque
        int head = lbdq.element();
        System.out.println("The head of lbdq: " + head);
    }
}


输出
The LinkedBlockingDeque, lbdq contains:
[22, 125, 723, 172, 100]
The LinkedBlockingDeque, lbdq contains 22
The head of lbdq: 22

3. 删除元素

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

Java


// Java Program for removing elements from a
// LinkedBlockingDeque
import java.util.concurrent.*;
public class RemovingElements {
    public static void main(String[] args)
    {
        // Instantiate an object of LinkedBlockingDeque
        // named lbdq
        BlockingQueue<Integer> lbdq
            = new LinkedBlockingDeque<Integer>();
        // Add elements using add()
        lbdq.add(75);
        lbdq.add(86);
        lbdq.add(13);
        lbdq.add(44);
        lbdq.add(10);
        // Print the elements of lbdq on the console
        System.out.println(
            "The LinkedBlockingDeque, lbdq contains:");
        System.out.println(lbdq);
        // Remove elements using remove();
        lbdq.remove(86);
        lbdq.remove(44);
        // Trying to remove an element
        // that doesn't exist
        // in the LinkedBlockingDeque
        lbdq.remove(1);
        // Print the elements of lbdq on the console
        System.out.println(
            "\nThe LinkedBlockingDeque, lbdq contains:");
        System.out.println(lbdq);
    }
}
输出
The LinkedBlockingDeque, lbdq contains:
[75, 86, 13, 44, 10]

The LinkedBlockingDeque, lbdq contains:
[75, 13, 10]

4. 迭代元素

要迭代 LinkedBlockingDeque 的元素,我们可以创建一个迭代器并使用 Iterable 接口(Java 集合框架的根)的方法来访问元素。 Iterable 的 next() 方法返回任何集合的元素。

Java


// Java Program to iterate 
// through the LinkedBlockingDeque
import java.util.Iterator;
import java.util.concurrent.*;
public class IteratingThroughElements {
    public static void main(String[] args) {
         
        // Instantiate an object of LinkedBlockingDeque named lbdq
        BlockingQueue<Integer> lbdq = new LinkedBlockingDeque<Integer>();
         
        // Add elements using add()
        lbdq.add(166);
        lbdq.add(246);
        lbdq.add(66);
        lbdq.add(292);
        lbdq.add(98);
         
        // Create an iterator to traverse lbdq
        Iterator<Integer> lbdqIter = lbdq.iterator();
         
        // Print the elements of lbdq on to the console
        System.out.println("The LinkedBlockingDeque, lbdq contains:");
         
        for(int i = 0; i<lbdq.size(); i++)
        {
            System.out.print(lbdqIter.next() + " ");
        }        
    }
}
输出
The LinkedBlockingDeque, lbdq contains:
166 246 66 292 98 

BlockingQueue的方法

METHOD

DESCRIPTION

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

接口 java.util.Collection 中声明的方法

METHOD

DESCRIPTION

addAll(集合 <? 扩展 E> c) 将指定集合中的所有元素添加到此集合中(可选操作)。
clear() 从此集合中删除所有元素(可选操作)。
containsAll(集合<?> c) 如果此集合包含指定集合中的所有元素,则返回 true。
equals(Object o) 比较指定对象与此集合是否相等。
hashCode() 返回此集合的哈希码值。
isEmpty() 如果此集合不包含任何元素,则返回 true。
iterator() 返回此集合中元素的迭代器。
parallelStream() 返回一个可能并行的 Stream 并以此集合作为其源。
移除全部(集合<?> c) 删除指定集合中也包含的所有该集合的元素(可选操作)。
removeIf(Predicate<? super E> 过滤器) 删除此集合中满足给定谓词的所有元素。
keepAll(集合<?> c) 仅保留此集合中包含在指定集合中的元素(可选操作)。
size() 返回此集合中的元素数量。
spliterator() 在此集合中的元素上创建Spliterator
stream() 返回以此集合作为源的顺序 Stream。
toArray() 返回一个包含此集合中所有元素的数组。
toArray(IntFunction<T[]> 生成器) 返回一个包含此集合中所有元素的数组,使用提供的生成器函数分配返回的数组。
toArray(T[] a) 返回一个包含该集合中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。

接口 java.lang.Iterable 中声明的方法

METHOD

DESCRIPTION

Iterable forEach() 对 Iterable 的每个元素执行给定的操作,直到处理完所有元素或该操作引发异常。

接口 java.util.Queue 中声明的方法

METHOD

DESCRIPTION

Queue element() 检索但不删除此队列的头部。
Queue peek() 检索但不删除此队列的头部,如果此队列为空,则返回 null。
Queue poll() 检索并删除此队列的头部,如果此队列为空,则返回 null。
BlockingQueue 检索并删除此队列的头部。

BlockingQueue 方法的行为

以下是 BlockingQueue 提供的用于对队列进行插入、删除和检查操作的方法。如果未立即满足请求的操作,四组方法中的每组方法的行为都会有所不同。

  • 抛出异常:如果请求的操作未立即满足,则会抛出异常。
  • 特别值:如果操作没有立即满足,则返回一个特殊值。
  • Blocks:如果尝试的操作未立即满足,则方法调用将被阻止,并等待直到执行。
  • 超时:返回一个特殊值,告诉操作是否成功。如果请求的操作无法立即执行,则该方法调用会阻塞,直到可以执行为止,但等待的时间不会超过给定的超时时间。
操作 抛出异常 特别值 积木 超时
插入 BlockingQueue add() BlockingQueue offer() 把(e) BlockingQueue offer()
Remove BlockingQueue remove() BlockingQueue poll() BlockingQueue take() BlockingQueue poll()
检查 element() peek() 不适用 不适用

参考:https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/BlockingQueue.html



相关用法


注:本文由纯净天空筛选整理自Rajput-Ji大神的英文原创作品 BlockingQueue Interface in Java。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。