文章目录
ConcurrentLinkedDeque
ConcurrentLinkedDeque
是 Java 并发工具包(java.util.concurrent
包)中的一个线程安全的双端队列(Deque)实现,实现了 Deque
接口。它使用了链表结构,并且针对高并发环境进行了优化,非常适合用于多线程环境中需要安全地并发访问双端队列的情况。ConcurrentLinkedDeque
不使用锁来保证线程安全,而是通过 CAS(Compare and Swap)原子操作来实现线程安全。
特点
-
非阻塞:
ConcurrentLinkedDeque
使用一种非阻塞的算法来实现并发操作,允许多个线程同时进行插入、删除和获取操作,而不需要进行锁定或阻塞。 -
线程安全:
ConcurrentLinkedDeque
提供了线程安全的操作,可以在多线程环境中使用而无需额外的同步操作。 -
双向链表:
ConcurrentLinkedDeque
是一个双向链表,可以在队列的头部和尾部进行插入、删除和获取操作。 -
无界容量:
ConcurrentLinkedDeque
没有容量限制,可以根据需要动态添加和移除元素。
构造方法
- 创建一个空的
ConcurrentLinkedDeque
。
ConcurrentLinkedDeque()
- 创建一个包含给定集合中所有元素的
ConcurrentLinkedDeque
,元素存储顺序为集合迭代器返回元素的顺序。如果给定集合为空,则创建一个空的ConcurrentLinkedDeque
。
ConcurrentLinkedDeque(Collection<? extends E> collection)
常用方法
-
addFirst(E e)
: 将指定元素插入到双端队列的头部,如果插入成功则返回true
,否则返回false
。 -
addLast(E e)
: 将指定元素插入到双端队列的尾部,如果插入成功则返回true
,否则返回false
。 -
offerFirst(E e)
: 将指定元素插入到双端队列的头部,如果插入成功则返回true
,否则返回false
。 -
offerLast(E e)
: 将指定元素插入到双端队列的尾部,如果插入成功则返回true
,否则返回false
。 -
removeFirst()
: 移除并返回双端队列的头部元素,如果队列为空,则抛出NoSuchElementException
异常。 -
removeLast()
: 移除并返回双端队列的尾部元素,如果队列为空,则抛出NoSuchElementException
异常。 -
pollFirst()
: 移除并返回双端队列的头部元素,如果队列为空则返回null
。 -
pollLast()
: 移除并返回双端队列的尾部元素,如果队列为空则返回null
。 -
getFirst()
: 返回双端队列的头部元素,但不移除该元素。 -
getLast()
: 返回双端队列的尾部元素,但不移除该元素。 -
peekFirst()
: 返回双端队列的头部元素,如果队列为空则返回 null -
peekLast()
: 返回双端队列的尾部元素,如果队列为空则返回 null -
contains(Object o)
: 判断双端队列是否包含指定的元素。 -
isEmpty()
: 判断双端队列是否为空。 -
size()
: 返回双端队列的元素个数。 -
iterator()
: 返回在此双端队列中元素上按顺序进行迭代的迭代器。 -
descendingIterator()
: 返回在此双端队列中元素上按逆序进行迭代的迭代器。 -
spliterator()
: 创建一个分离器并行迭代双端队列中的元素。
使用示例
以下是一个简单的 ConcurrentLinkedDeque
使用示例,展示了如何创建一个双端队列,并在其上执行基本的操作:
import java.util.concurrent.ConcurrentLinkedDeque;
public class ConcurrentLinkedDequeExample {
public static void main(String[] args) {
// 创建 ConcurrentLinkedDeque
ConcurrentLinkedDeque<String> deque = new ConcurrentLinkedDeque<>();
// 添加元素
deque.offerFirst("Apple");
deque.offerLast("Banana");
deque.offerFirst("Cherry");
// 打印队列
System.out.println("双端队列初始状态: " + deque);
// 创建线程向队列中添加元素
Thread addThread = new Thread(() -> {
deque.offerFirst("Durian");
deque.offerLast("Elderberry");
System.out.println("添加元素后的双端队列: " + deque);
});
// 创建线程从队列中取出元素
Thread pollThread = new Thread(() -> {
while (!deque.isEmpty()) {
String itemFirst = deque.pollFirst();
String itemLast = deque.pollLast();
if (itemFirst != null) {
System.out.println("从队列前端取出元素: " + itemFirst);
}
if (itemLast != null) {
System.out.println("从队列尾端取出元素: " + itemLast);
}
}
});
// 启动线程
addThread.start();
pollThread.start();
try {
// 等待线程结束
addThread.join();
pollThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("主线程被中断");
}
// 打印最终队列状态
System.out.println("最终双端队列状态: " + deque);
}
}
注意事项
使用 ConcurrentLinkedDeque
时,应注意以下问题:
- 弱一致性:
ConcurrentLinkedDeque
提供的是弱一致性保证,这意味着如果存在多个线程并发操作双端队列,双端队列的顺序可能会发生变化。 - 非阻塞特性:
ConcurrentLinkedDeque
的pollFirst
和pollLast
方法在队列为空时会立即返回null
,而不是阻塞等待。这意味着如果你需要等待双端队列中有元素,应该考虑使用BlockingDeque
。 - 迭代器快照:
ConcurrentLinkedDeque
的iterator
方法返回的是一个快照迭代器,不会反映迭代期间双端队列的变化。如果需要实时迭代双端队列中的元素,可以考虑使用其他机制,如轮询。 - 内存回收:
ConcurrentLinkedDeque
中的节点在没有引用指向时会被垃圾回收。因此,如果双端队列中的元素不再被引用,相应的节点也会被回收。