Java中的LinkedBlockingDeque和示例

Java中的LinkedBlockingDeque和示例

Java中的 LinkedBlockingDeque 类是Java Collection Framework的一部分。它是JDK1.6中引入的,属于 java.util.concurrent 包。它是一个Deque(双向队列),如果一个线程尝试在Deque为空时从中取出元素,则会阻塞该线程。它实现了BlockingDeque并基于链接节点提供可选的有界功能。通过在构造函数中传递所需的大小,可以实现可选的有界性,并有助于防止内存浪费。当未指定时,默认情况下将容量视为 Integer.MAX_VALUE 。该类及其迭代器实现了 CollectionIterator 接口的所有可选方法。LinkedBlockingDeque提供的实现是 线程安全的 。类中的所有排队方法均使用内部的ReentrantLock以原子方式实现它们的效果。

Java中的LinkedBlockingDeque是一个线程安全和并发实现Deque接口的类,它使用链表来存储其元素。LinkedBlockingDeque可以用作传统的堆栈或队列,具体取决于您用于插入和删除元素的方法。

以下是如何在Java中使用LinkedBlockingDeque的示例:

import java.util.concurrent.LinkedBlockingDeque;
 
public class LinkedBlockingDequeExample {
    public static void main(String[] args) throws InterruptedException {
        LinkedBlockingDeque<Integer> deque = new LinkedBlockingDeque<>(5);
         
        // 往deque中添加元素
        deque.offerFirst(1);
        deque.offerLast(2);
        deque.offerFirst(3);
        deque.offerLast(4);
         
        // 从deque中移除元素
        System.out.println(deque.pollFirst()); // 输出:3
        System.out.println(deque.pollLast()); // 输出:4
    }
}

输出

3
4

在此示例中,我们使用offerFirst和offerLast方法创建一个容量为5的LinkedBlockingDeque并向其添加元素。然后,我们使用pollFirst和pollLast方法从deque中删除元素并将结果打印到控制台。

使用LinkedBlockingDeque的优点:

  1. 线程安全:LinkedBlockingDeque类是线程安全的,这意味着多个线程可以同时访问它而不会遇到数据损坏。
  2. 高效:LinkedBlockingDeque类为从deque的两端插入和删除元素提供常量时间性能,因此在需要执行多个添加和删除操作的情况下,它是一个不错的选择。
  3. 可扩展:LinkedBlockingDeque类使用链表来存储其元素,这使其具有可扩展性,并适用于高性能和并发应用程序。
  4. 高并发:LinkedBlockingDeque类使用无锁算法,这意味着多个线程可以同时访问deque而无需锁定,因此适用于高并发应用程序。
  5. 阻塞行为:LinkedBlockingDeque类为插入和删除元素提供了阻塞行为,这意味着尝试将元素插入到完全deque或从空deque中删除元素的线程将被阻塞,直到有空间或元素可用。

使用LinkedBlockingDeque的缺点:

  1. 更大的内存开销:LinkedBlockingDeque类使用连续链表来存储其元素,这意味着它需要比基于数组实现的ArrayDeque类更多的内存开销。
  2. 有限的容量:LinkedBlockingDeque类具有限制的容量,可以在创建deque时指定。如果尝试向已满的deque插入元素,则线程将被阻塞,直到空间可用。

参考书籍:

由Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowbeer、David Holmes和Doug Lea编写的《Java Concurrency in Practice》是Java并发编程的全面指南。

LinkedBlockingDeque的层次结构

Java中的LinkedBlockingDeque和示例

它实现了 SerializableIterable ** 、 **Collection ** 、BlockingDeque、BlockingQueue、Deque、Queue接口,并扩展了AbstractQueue和AbstractCollection类。
**声明:

public class LinkedBlockingDeque extends AbstractQueue implements BlockingDeque, Serializable

在这里, E 是存储在集合中的元素类型。

Java LinkedBlockingDeque中的构造函数

要创建LinkedBlockingDeque的实例,我们需要从 java.util.concurrent 包中导入它。

1. LinkedBlockingDeque() :这个构造函数用于构造一个空的deque。在这种情况下,容量设置为Integer.MAX_VALUE。

LinkedBlockingDeque<E> lbd = new LinkedBlockingDeque<E>();

2. LinkedBlockingDeque(int capacity) :此构造函数创建具有给定(固定)容量的LinkedBlockingDeque。

LinkedBlockingDeque<E> lbd = new LinkedBlockingDeque​<E>(int capacity);

**3. LinkedBlockingDeque(Collection c) ** :此构造函数用于构造具有Collection作为参数的deque的元素。

LinkedBlockingDeque​<E> lbd = new LinkedBlockingDeque​<E>(Collection<? extends E> c);

下面是一个示例程序,用于说明Java LinkedBlockingDeque:

示例1:

// Java程序演示LinkedBlockingDeque
 
import java.util.concurrent.LinkedBlockingDeque;
import java.util.*;
 
public class LinkedBlockingDequeDemo {
    public static void main(String[] args)
        throws InterruptedException
    {
 
        // 创建LinkedBlockingDeque对象,使用LinkedBlockingDeque()构造函数
        LinkedBlockingDeque<Integer> LBD
            = new LinkedBlockingDeque<Integer>();
 
        // 在LinkedBlockingDeque末尾添加数字
        LBD.add(7855642);
        LBD.add(35658786);
        LBD.add(5278367);
        LBD.add(74381793);
 
        // 打印Deque
        System.out.println("Linked Blocking Deque1: "
                           + LBD);
        System.out.println("Linked Blocking Deque1的大小: "
                           + LBD.size());
 
        // 创建LinkedBlockingDeque对象,使用LinkedBlockingDeque(int capacity)构造函数
        LinkedBlockingDeque<Integer> LBD1
            = new LinkedBlockingDeque<Integer>(3);
 
        // 在LinkedBlockingDeque末尾添加数字
        LBD1.add(7855642);
        LBD1.add(35658786);
        LBD1.add(5278367);
 
        try {
            // 添加第四个元素,对于Deque已满,将抛出异常
            LBD1.add(74381793);
        }
        catch (Exception e) {
            System.out.println("异常: " + e);
        }
 
        // 打印Deque
        System.out.println("Linked Blocking Deque2: "
                           + LBD1);
        System.out.println("Linked Blocking Deque2的大小: "
                           + LBD1.size());
 
        // 创建LinkedBlockingDeque对象,使用LinkedBlockingDeque(Collection c)构造函数
        LinkedBlockingDeque<Integer> LBD2
            = new LinkedBlockingDeque<Integer>(LBD1);
 
        // 打印Deque
        System.out.println("Linked Blocking Deque3: "
                           + LBD2);
    }
}

输出

Linked Blocking Deque1: [7855642, 35658786, 5278367, 74381793]
Linked Blocking Deque1的大小: 4
异常: java.lang.IllegalStateException: Deque full
Linked Blocking Deque2: [7855642, 35658786, 5278367]
Linked Blocking Deque2的大小: 3
Linked Blocking Deque3: [7855642, 35658786, 5278367]

示例2:

// Java演示LinkedBlockingDeque的方法
 
import java.util.concurrent.LinkedBlockingDeque;
import java.util.*;
 
public class LinkedBlockingDequeDemo {
    public static void main(String[] args)
        throws InterruptedException
    {
 
        // 创建LinkedBlockingDeque对象
        LinkedBlockingDeque<Integer> LBD
            = new LinkedBlockingDeque<Integer>();
 
        // 使用add()方法向LinkedBlockingDeque的末尾添加数字
        LBD.add(7855642);
        LBD.add(35658786);
        LBD.add(5278367);
        LBD.add(74381793);
 
        // 打印双端队列
        System.out.println("Linked Blocking Deque: "
                           + LBD);
 
        // 使用size()方法删除元素后打印队列大小
        System.out.println("Linked Blocking Deque的大小: "
                           + LBD.size());
 
        // 使用removeFirst()方法删除前面的元素并打印
        System.out.println("第一个元素: "
                           + LBD.removeFirst());
 
        // 打印双端队列
        System.out.println("Linked Blocking Deque: "
                           + LBD);
 
        // 使用size()方法删除元素后打印队列大小
        System.out.println("Linked Blocking Deque的大小: "
                           + LBD.size());
 
        // 使用offer()方法向LinkedBlockingDeque的末尾添加数字
        LBD.offer(20);
 
        // 打印双端队列
        System.out.println("Linked Blocking Deque: "
                           + LBD);
 
        // 使用size()方法删除元素后打印队列大小
        System.out.println("Linked Blocking Deque的大小: "
                           + LBD.size());
    }
}

输出

Linked Blocking Deque: [7855642, 35658786, 5278367, 74381793]
Linked Blocking Deque的大小: 4
第一个元素: 7855642
Linked Blocking Deque: [35658786, 5278367, 74381793]
Linked Blocking Deque的大小: 3
Linked Blocking Deque: [35658786, 5278367, 74381793, 20]
Linked Blocking Deque的大小: 4

基本操作

1. 添加元素

LinkedBlockingDeque提供了各种方法,在两端添加或插入元素,包括add(E e)、addAll(Collection c)、addFirst(E e)、addLast(E e)等。

// Java程序演示添加元素到LinkedBlockingDeque中
 
import java.util.concurrent.LinkedBlockingDeque;
import java.util.*;
 
public class AddingElementsExample {
    public static void main(String[] args)
        throws IllegalStateException
    {
 
        // 创建LinkedBlockingDeque对象
        LinkedBlockingDeque<Integer> lbd
            = new LinkedBlockingDeque<Integer>();
 
        // 将数字添加到LinkedBlockingDeque的末尾
        lbd.add(7855642);
 
        // 在头部或前面添加整数
        lbd.addFirst(35658786);
 
        // 在尾部或末尾添加整数
        lbd.addLast(5278367);
 
        // 打印队列
        System.out.println("Linked Blocking Deque: " + lbd);
           
          // 创建ArrayList集合对象
        ArrayList<Integer> ArrLis
            = new ArrayList<Integer>();
   
        // 往ArrayList中添加数字
        ArrLis.add(55);
        ArrLis.add(66);
        ArrLis.add(77);
        ArrLis.add(88);
   
        // 打印ArrayList
        System.out.println("ArrayList: " + ArrLis);
   
        // 使用addAll()方法将ArrayList的所有元素添加到LinkedBlockingDeque中
        lbd.addAll(ArrLis);
   
        // 打印deque
        System.out.println("Linked Blocking Deque: " + lbd);
    }
}

输出

Linked Blocking Deque: [35658786, 7855642, 5278367]
ArrayList: [55, 66, 77, 88]
Linked Blocking Deque: [35658786, 7855642, 5278367, 55, 66, 77, 88]

2. 删除元素

LinkedBlockingDeque 提供了不同的方法来从两端删除或移除元素。它们是 remove()、removeFirst()、removeLast() 等。

// Java程序演示删除LinkedBlockingDeque的元素
 
import java.util.concurrent.LinkedBlockingDeque;
import java.util.*;
 
public class RemovingElementsExample {
    public static void main(String[] args)
        throws InterruptedException
    {
 
        // 创建LinkedBlockingDeque对象
        LinkedBlockingDeque<Integer> lbd
            = new LinkedBlockingDeque<Integer>();
 
        // 向 LinkedBlockingDeque 的末尾添加数字
        lbd.add(7855642);
        lbd.add(35658786);
        lbd.add(5278367);
        lbd.add(74381793);
        lbd.add(12345566);
 
        // 打印 Dequeue
        System.out.println("Linked Blocking Deque: " + lbd);
 
        // 删除第一个元素
        lbd.remove();
 
        // 打印修改后的Deque
        System.out.println("Linked Blocking Deque: " + lbd);
 
        // 删除第一个元素
        lbd.removeFirst();
 
        // 打印修改后的Deque
        System.out.println("Linked Blocking Deque: " + lbd);
 
        // 删除最后一个元素
        lbd.removeLast();
 
        // 打印修改后的Deque
        System.out.println("Linked Blocking Deque: " + lbd);
    }
}

输出

Linked Blocking Deque: [7855642, 35658786, 5278367, 74381793, 12345566]
Linked Blocking Deque: [35658786, 5278367, 74381793, 12345566]
Linked Blocking Deque: [5278367, 74381793, 12345566]
Linked Blocking Deque: [5278367, 74381793]

输出

Linked Blocking Deque: [7855642, 35658786, 5278367, 74381793, 12345566]
Linked Blocking Deque: [35658786, 5278367, 74381793, 12345566]
Linked Blocking Deque: [5278367, 74381793, 12345566]
Linked Blocking Deque: [5278367, 74381793]

3. 遍历

LinkedBlockingDeque 的 iterator() 方法以正确的顺序返回迭代器中这个 deque 的元素。元素将按从头到尾的顺序返回。返回的迭代器是“弱一致性”迭代器。

// Java程序演示如何迭代LinkedBlockingDeque
 
import java.util.concurrent.LinkedBlockingDeque;
import java.util.*;
 
public class IteratingExample {
    public static void main(String[] args)
 
    {
 
        // 创建 LinkedBlockingDeque 对象
        LinkedBlockingDeque<Integer> LBD
            = new LinkedBlockingDeque<Integer>();
 
        // 向 LinkedBlockingDeque 前面添加数字
        LBD.addFirst(7855642);
        LBD.addFirst(35658786);
        LBD.addFirst(5278367);
        LBD.addFirst(74381793);
 
        // 调用 LinkedBlockingDeque 的 iterator()方法
        Iterator iteratorVals = LBD.iterator();
 
        // 打印从 PriorityBlockingQueue 创建的迭代器的元素
        System.out.println("The iterator values"
            + " of LinkedBlockingDeque are:");
 
        // 使用迭代器打印元素
        while (iteratorVals.hasNext()) {
            System.out.println(iteratorVals.next());
        }
    }
}

输出

The iterator values of LinkedBlockingDeque are:
74381793
5278367
35658786
7855642
LinkedBlockingDeque的迭代器值为:
74381793
5278367
35658786
7855642

LinkedBlockingDeque的方法

方法 描述
add​(E e) 将指定元素插入到双端队列的末尾,除非会违反容量限制。
addAll​(Collection c) | 将指定集合中的所有元素以它们在指定集合迭代器返回顺序中的顺序添加到双端队列的末尾。
addFirst​(E e) | 如果可以立即执行而不违反容量限制,则将指定元素插入到双端队列的开头,如果当前没有空间,则抛出IllegalStateException。
addLast​(E e) | 如果可以立即执行而不违反容量限制,则将指定元素插入到双端队列的末尾,如果当前没有空间,则抛出IllegalStateException。
clear() | 原子性地从该双端队列中移除所有元素。
contains​(Object o) | 如果此双端队列包含指定元素,则返回true。
descendingIterator() | 返回一个以相反的顺序遍历双端队列中所有元素的迭代器。
drainTo​(Collection c) | 移除此队列中所有可用的元素,并将它们添加到指定的集合中。
drainTo​(Collection c, int maxElements) | 最多从此队列中移除给定数量的可用元素,并将它们添加到指定的集合中。
element() | 检索但不移除由该双端队列表示的队列的头部元素。
forEach​(Consumer action) | 对 Iterable 的每个元素执行给定的操作,直到所有元素都已处理或操作引发异常。
getFirst() | 检索但不移除该双端队列的第一个元素。
getLast() | 检索但不移除该双端队列的最后一个元素。
iterator() | 返回一个按适当顺序遍历该双端队列中所有元素的迭代器。
offer​(E e) | 将指定元素插入到该双端队列表示的队列中(换句话说,将其插入到该双端队列的尾部),如果可以立即执行而不违反容量限制,则返回true;如果当前没有空间,则返回false。
offer​(E e, long timeout, TimeUnit unit) | 将指定元素插入到该双端队列表示的队列中(换句话说,将其插入到该双端队列的尾部),如果必要,等待指定的等待时间,直到空间变为可用。
offerFirst​(E e) | 如果可以立即执行而不违反容量限制,则将指定元素插入到双端队列的开头,返回true;如果当前没有空间,则返回false。
offerFirst​(E e, long timeout, TimeUnit unit) | 如果必要,等待指定的等待时间,直到空间变为可用,然后将指定元素插入到双端队列的开头。
offerLast​(E e) | 如果可以立即执行而不违反容量限制,则将指定元素插入到双端队列的末尾,返回true;如果当前没有空间,则返回false。
offerLast​(E e, long timeout, TimeUnit unit) | 如果必要,等待指定的等待时间,直到空间变为可用,然后将指定元素插入到双端队列的末尾。
peek() | 检索但不移除由该双端队列表示的队列的头部元素,如果该队列为空,则返回null。
peekFirst() | 检索但不移除该双端队列的第一个元素,如果该双端队列为空,则返回null。
peekLast() | 检索但不移除该双端队列的最后一个元素,如果该双端队列为空,则返回null。
poll() | 检索并删除由该双端队列表示的队列的头部元素,如果该队列为空,则返回null。
pollFirst() | 检索并删除该双端队列的第一个元素,如果该双端队列为空,则返回null。
pollLast() | 检索并删除该双端队列的最后一个元素,如果该双端队列为空,则返回null。
pop() | 弹出由该双端队列表示的堆栈的顶部元素。
push​(E e) | 将指定元素推送到此双端队列所表示的堆栈上。
remove() | 检索并删除由该双端队列表示的队列的头部元素。
remove​(Object o) | 从该双端队列中删除指定元素的一个实例(如果存在)。
removeFirst() | 检索并删除该双端队列的第一个元素。
removeFirstOccurrence​(Object o) | 从此双端队列中删除指定元素的第一次出现(如果存在)。
removeLast() | 检索并删除该双端队列的最后一个元素。
removeLastOccurrence​(Object o) | 从此双端队列中删除指定元素的最后一次出现(如果存在)。
spliterator() | 创建一个可遍历的Spliterator,该Spliterator遍历该双端队列中的元素。
size() | 返回此双端队列中的元素数量。
stream() | 返回此双端队列作为源的顺序Stream。
toArray() | 返回包含此双端队列中所有元素的数组。
toArray​(T[] a) | 返回一个包含此双端队列中所有元素的数组。这个数组的运行时类型是指定数组的运行时类型。
双端队列Deque接口提供的方法 offerLast​(E e) | 如果可以在不违反容量限制的情况下立即这样做,则将指定的元素插入此deque的末尾,并在成功时返回true,如果当前没有可用空间,则返回false。
offerLast​(E e, long timeout, TimeUnit unit) | 在必要时等待指定的等待时间,以使空间可用,并将指定的元素插入此deque的末尾。
pop() | 从此deque表示的栈中弹出一个元素。
push​(E e) | 如果可以立即这样做而不违反容量限制,则将元素推入由此deque表示的栈(换句话说,在此deque的头部),如果当前没有可用空间,则抛出IllegalStateException。
put​(E e) | 将指定的元素插入此deque表示的队列中(换句话说,在此deque的尾部),必要时等待使空间可用。
putFirst​(E e) | 将指定的元素插入此deque的前面,在必要时等待以使空间可用。
putLast​(E e) | 在必要时等待以使空间可用,并在此deque的末尾插入指定的元素。
remainingCapacity() | 返回此deque可以理想地(在没有内存或资源限制的情况下)接受而不阻止的其他元素的数量。
remove() | 检索并从此deque表示的队列中删除头。
remove(Object o) | 从此deque中删除第一次出现的指定元素。
removeAll​(Collection c)
删除此集合中也包含在指定集合中的所有元素(可选操作)。
removeFirst() 检索并删除此deque的第一个元素。
removeIf​(Predicate filter) | 删除此集合的所有满足给定谓词的元素。
removeLast() | 检索并删除此deque的最后一个元素。
retainAll​(Collection c)
仅保留此集合中包含在指定集合中的元素(可选操作)。
size() 返回此deque中的元素数。
spliterator() 返回此deque中元素的Spliterator。
toArray() 返回一个包含此deque中所有元素的数组,以正确的顺序(从第一个到最后一个元素)。
toArray​(T[] a) 返回一个包含此deque中所有元素的数组,以正确的顺序(从第一个到最后一个元素);返回的数组的运行时类型是指定数组的类型。

java.util.AbstractCollection类中声明的方法

方法 描述
containsAll​(Collection c) | 如果此集合包含指定集合中的所有元素,则返回true。
isEmpty() | 如果此集合不包含任何元素,则返回true。
toString() | 返回此集合的字符串表示。

### java.util.concurrent.BlockingDeque接口中声明的方法

方法 | 描述
—|—
peek() | 检索但不删除由此双端队列表示的队列的头部(换句话说,该双端队列的第一个元素),如果此双端队列为空,则返回null。
poll() | 检索并删除由此双端队列表示的队列的头部(换句话说,该双端队列的第一个元素),如果此双端队列为空,则返回null。
poll​(long timeout, TimeUnit unit) | 检索并删除由此双端队列表示的队列的头部(换句话说,该双端队列的第一个元素),如果需要,等待指定时间以使元素可用。
pollFirst​(long timeout, TimeUnit unit) | 检索并删除此双端队列的第一个元素,如果需要,等待指定时间以使元素可用。
pollLast​(long timeout, TimeUnit unit) | 检索并删除此双端队列的最后一个元素,如果需要,等待指定时间以使元素可用。
removeFirstOccurrence​(Object o) | 从此双端队列中删除指定元素的第一个匹配项。
removeLastOccurrence​(Object o) | 从此双端队列中删除指定元素的最后一个匹配项。
take() | 检索并删除由此双端队列表示的队列的头部(换句话说,该双端队列的第一个元素),如果需要,则等待,直到有一个元素可用。
takeFirst() | 检索并删除此双端队列的第一个元素,如果需要,则等待,直到有一个元素可用。
takeLast() | 检索并删除此双端队列的最后一个元素,如果需要,则等待,直到有一个元素可用。

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

方法 | 描述
—|—
containsAll​(Collection c)

如果此集合包含指定集合中的所有元素,则返回 true。
equals​(Object o) 将指定对象与此集合进行比较以检查相等。
hashCode() 返回此集合的哈希码值。
isEmpty() 如果此集合不包含元素,则返回 true。
parallelStream() 返回以此集合为源的可能并行流。
stream() 返回以此集合为源的顺序流。
toArray​(IntFunction<T[]> generator) 使用提供的生成函数分配返回的数组,返回包含此集合中所有元素的数组。

在接口 java.util.Deque 中声明的方法

方法 描述
peekFirst() 检索但不删除此双端队列的第一个元素;如果此双端队列为空,则返回 null。
peekLast() 检索但不删除此双端队列的最后一个元素;如果此双端队列为空,则返回 null。
pollFirst() 检索并删除此双端队列的第一个元素;如果此双端队列为空,则返回 null。
pollLast() 检索并删除此双端队列的最后一个元素;如果此双端队列为空,则返回 null。

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

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程