LinkedBlockingDeque<E>
和 ConcurrentLinkedDeque<E>
都是 Java 集合框架中的双端队列实现。它们都允许在两端插入和移除元素,并且是线程安全的。
LinkedBlockingDeque
LinkedBlockingDeque<E>
是一个基于链表的阻塞双端队列,它实现了 BlockingDeque
接口。当尝试从空队列中取出元素或向满队列中添加元素时,如果有必要,它会阻塞当前线程直到操作成功。
方法如下:
pollLast()
: 从队列的尾部移除并返回元素,如果队列为空则返回null。removeFirstOccurrence(Object)
: 从队列中移除第一次出现的指定元素(如果存在),成功时返回true,否则返回false。putLast(E)
: 将指定的元素添加到队列的尾部。remainingCapacity()
: 返回队列剩余的容量。drainTo(Collection<E>, int)
: 移除队列中的最多指定数量的元素并将它们添加到给定的集合中,返回实际移除的元素数量。element()
: 返回队列头部的元素但不移除它,如果队列为空则抛出异常。peekFirst()
: 返回队列头部的元素但不移除它,如果队列为空则返回null。removeLastOccurrence(Object)
: 从队列中移除最后一次出现的指定元素(如果存在),成功时返回true,否则返回false。drainTo(Collection<E>)
: 移除队列中的所有元素并将它们添加到给定的集合中,返回实际移除的元素数量。put(E)
: 将指定的元素添加到队列的尾部。remove(Object)
: 从队列中移除指定的元素(如果存在),成功时返回true,否则返回false。pollLast(long, TimeUnit)
: 在指定的时间内从队列的尾部移除并返回元素,如果在指定时间内没有元素可用则返回null。takeFirst()
: 移除并返回队列头部的元素,如果队列为空则阻塞等待直到有元素可用。peek()
: 返回队列头部的元素但不移除它,如果队列为空则返回null。remove()
: 移除并返回队列头部的元素,如果队列为空则抛出异常。contains(Object)
: 检查队列是否包含指定的元素。offer(E, long, TimeUnit)
: 将指定的元素添加到队列的尾部,在指定的时间内等待空间可用,成功时返回true,否则返回false。toString()
: 返回队列的字符串表示形式。offerLast(E, long, TimeUnit)
: 将指定的元素添加到队列的尾部,在指定的时间内等待空间可用,成功时返回true,否则返回false。take()
: 移除并返回队列头部的元素,如果队列为空则阻塞等待直到有元素可用。pollFirst(long, TimeUnit)
: 在指定的时间内从队列的头部移除并返回元素,如果在指定时间内没有元素可用则返回null。size()
: 返回队列中的元素数量。push(E)
: 将指定的元素添加到队列的头部。add(E)
: 将指定的元素添加到队列的尾部,成功时返回true,否则抛出异常。pollFirst()
: 从队列的头部移除并返回元素,如果队列为空则返回null。poll()
: 从队列的头部移除并返回元素,如果队列为空则返回null。takeLast()
: 移除并返回队列尾部的元素,如果队列为空则阻塞等待直到有元素可用。iterator()
: 返回一个迭代器,用于遍历队列中的元素。offerFirst(E)
: 将指定的元素添加到队列的头部,成功时返回true,否则抛出异常。offer(E)
: 将指定的元素添加到队列的尾部,成功时返回true,否则抛出异常。descendingIterator()
: 返回一个逆序迭代器,用于从队列尾部到头部遍历元素。offerLast(E)
: 将指定的元素添加到队列的尾部,成功时返回true,否则抛出异常。spliterator()
: 返回一个分割迭代器,用于并行遍历队列中的元素。addFirst(E)
: 将指定的元素添加到队列的头部。removeLast()
: 移除并返回队列尾部的元素,如果队列为空则抛出异常。toArray(T[])
: 将队列中的元素转换为指定类型的数组。peekLast()
: 返回队列尾部的元素但不移除它,如果队列为空则返回null。pop()
: 移除并返回队列头部的元素,如果队列为空则抛出异常。clear()
: 清空队列中的所有元素。getFirst()
: 返回队列头部的元素但不移除它,如果队列为空则抛出异常。putFirst(E)
: 将指定的元素添加到队列的头部。removeFirst()
: 移除并返回队列头部的元素,如果队列为空则抛出异常。getLast()
: 返回队列尾部的元素但不移除它,如果队列为空则抛出异常。offerFirst(E, long, TimeUnit)
: 将指定的元素添加到队列的头部,在指定的时间内等待空间可用,成功时返回true,否则返回false。addLast(E)
: 将指定的元素添加到队列的尾部,成功时返回true,否则抛出异常。poll(long, TimeUnit)
: 在指定的时间内从队列的头部移除并返回元素,如果在指定时间内没有元素可用则返回null。toArray()
: 将队列中的元素转换为Object类型的数组。
应用场景:
- 生产者消费者模型:生产者线程向队列中添加元素,消费者线程从队列中取出元素进行处理。
- 缓冲区:用于在生产者和消费者之间传递数据,提高数据处理的效率。
- 任务调度:将任务添加到队列中,然后由工作线程按顺序执行这些任务。
示例代码:
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
public class LinkedBlockingDequeExample {
public static void main(String[] args) {
LinkedBlockingDeque<String> deque = new LinkedBlockingDeque<>(5);
// 生产者线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
deque.put("Element " + i);
System.out.println("Produced: Element " + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
// 消费者线程
new Thread(() -> {
while (true) {
try {
String element = deque.poll(2, TimeUnit.SECONDS);
if (element != null) {
System.out.println("Consumed: " + element);
} else {
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
ConcurrentLinkedDeque
ConcurrentLinkedDeque<E>
是一个基于链表的并发双端队列,它实现了 Deque
接口。与 LinkedBlockingDeque
不同,ConcurrentLinkedDeque
是非阻塞的,即它在尝试从空队列中取出元素或向满队列中添加元素时不会阻塞线程。相反,它会抛出异常或者返回特定的值(例如 null
)。
方法如下:
peek()
: 返回队列头部的元素,但不移除它。如果队列为空,则返回null。contains(Object)
: 检查队列是否包含指定的元素。size()
: 返回队列中的元素数量。poll()
: 移除并返回队列头部的元素。如果队列为空,则返回null。offer(E)
: 将指定的元素添加到队列的尾部。成功时返回true,否则返回false(例如,当空间不足时)。isEmpty()
: 检查队列是否为空。toArray(T[])
: 将队列中的元素转换为指定类型的数组。toArray()
: 将队列中的元素转换为Object类型的数组。add(E)
: 将指定的元素添加到队列的尾部。成功时返回true,否则抛出异常(例如,当空间不足时)。addAll(Collection<E>)
: 将指定集合中的所有元素添加到队列的尾部。成功时返回true,否则抛出异常(例如,当空间不足时)。spliterator()
: 返回一个用于遍历队列元素的Spliterator对象。remove(Object)
: 从队列中移除指定的元素(如果存在)。成功时返回true,否则返回false。iterator()
: 返回一个用于遍历队列元素的迭代器。
应用场景:
- 生产者消费者模型:生产者线程向队列中添加元素,消费者线程从队列中取出元素进行处理。
- 缓冲区:用于在生产者和消费者之间传递数据,提高数据处理的效率。
- 任务调度:将任务添加到队列中,然后由工作线程按顺序执行这些任务。
示例代码:
import java.util.concurrent.ConcurrentLinkedDeque;
public class ConcurrentLinkedDequeExample {
public static void main(String[] args) {
ConcurrentLinkedDeque<String> deque = new ConcurrentLinkedDeque<>();
// 生产者线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
deque.add("Element " + i);
System.out.println("Produced: Element " + i);
}
}).start();
// 消费者线程
new Thread(() -> {
while (!deque.isEmpty()) {
String element = deque.poll();
if (element != null) {
System.out.println("Consumed: " + element);
}
}
}).start();
}
}