Java中的BlockingDeque

Java中的BlockingDeque

在Java中,BlockingDeque是双端队列(Deque)的一种特殊形式。它允许在队列的两端插入或删除元素,并且支持阻塞操作。简而言之,它就是一个能够在生产者和消费者之间传递元素的数据结构。本文将详细讨论BlockingDeque在Java中的使用方法和一些示例代码。

核心接口和方法

BlockingDeque提供了一些核心接口和方法,如下所示:

  • addFirst(E e):在双端队列的头部添加一个元素,如队列满了,抛出IllegalStateException异常。
  • addLast(E e):在双端队列的尾部添加一个元素,如队列满了,抛出IllegalStateException异常。
  • offerFirst(E e):在双端队列的头部添加一个元素,如队列满了,直接返回false。
  • offerLast(E e):在双端队列的尾部添加一个元素,如队列满了,直接返回false。
  • putFirst(E e):在双端队列的头部添加一个元素,如队列满了,阻塞等待。
  • putLast(E e):在双端队列的尾部添加一个元素,如队列满了,阻塞等待。
  • takeFirst():从双端队列的头部取出一个元素,如队列为空,阻塞等待。
  • takeLast():从双端队列的尾部取出一个元素,如队列为空,阻塞等待。
  • pollFirst():从双端队列的头部取出一个元素,如队列为空,直接返回null。
  • pollLast():从双端队列的尾部取出一个元素,如队列为空,直接返回null。
  • removeFirst():从双端队列的头部删除一个元素,如队列为空,抛出NoSuchElementException异常。
  • removeLast():从双端队列的尾部删除一个元素,如队列为空,抛出NoSuchElementException异常。
  • peekFirst():查看双端队列的头部元素,如队列为空,直接返回null。
  • peekLast():查看双端队列的尾部元素,如队列为空,直接返回null。

示例代码

让我们来看一些示例代码,以更好地理解BlockingDeque的使用方法。

import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class Example {
    public static void main(String[] args) throws Exception {
        BlockingDeque<Integer> deque = new LinkedBlockingDeque<>(2);

        deque.addFirst(1);
        deque.addLast(2);

        // deque.addLast(3);// 抛出IllegalStateException异常

        deque.putFirst(0);

        System.out.println(deque.takeLast());// 2
        System.out.println(deque.takeFirst());// 0
        System.out.println(deque.pollLast());// 1
        System.out.println(deque.pollFirst());// null
    }
}

上述示例代码创建了一个容量为2的LinkedBlockingDeque,然后在其头部和尾部添加元素1和2。接着,在容量满的情况下,使用putFirst()方法将元素0添加到队列中去,该方法会一直阻塞直到队列有空余位置。最后,我们依次使用takeLast()、takeFirst()、pollLast()和pollFirst()方法取出元素,其中,takeXXX()方法是阻塞等待,而pollXXX()方法是直接返回null或者队列中的元素。

另外,BlockingDeque可以被用作生产者-消费者模式的并发队列。下面是一个示例:

import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class ProducerConsumer {
    public static void main(String[] args) {
        BlockingDeque<Integer> deque = new LinkedBlockingDeque<>(2);

        new Thread(new Producer(deque)).start();
        new Thread(new Consumer(deque)).start();
    }

    static class Producer implements Runnable {
        private final BlockingDeque<Integer> deque;

        Producer(BlockingDeque<Integer> deque) {
            this.deque = deque;
        }

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    deque.put(i);
                    System.out.println(Thread.currentThread().getName() + " 生产 " + i + " 成功");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static class Consumer implements Runnable {
        private final BlockingDeque<Integer> deque;

        Consumer(BlockingDeque<Integer> deque) {
            this.deque = deque;
        }

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Integer value = deque.take();
                    System.out.println(Thread.currentThread().getName() + " 消费 " + value + " 成功");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

上述示例代码创建了一个容量为2的LinkedBlockingDeque,并启动了一个生产者线程和一个消费者线程。在生产者线程中,循环向队列中添加元素,如果队列已满,则会阻塞等待。在消费者线程中,循环从队列中取出元素,如果队列为空,则会阻塞等待。

结论

BlockingDeque作为双端队列的一种特殊形式,具有阻塞的特性。它可以被用作生产者-消费者模式的并发队列,从而实现线程安全的数据交换。在实际应用中,我们可以根据业务场景选择不同的队列实现。当我们需要在队列的两端进行插入或删除操作,并且希望在队列已满或为空时进行阻塞等待时,BlockingDeque会是一个不错的选择。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程