前言
上一章我们讲了ConcurrentLinkedQueue, 这章我们要讲ConcurrentLinkedDeque通过类的名字上看,通过名字,我猜想基本原理应该和ConcurrentLinkedQueue是一样的,除了数据结构式双向链表以外,下面就具体研究,来看下自己的猜想是不是正确的
正文
类的描述
-
public class ConcurrentLinkedDeque<E> extends AbstractCollection<E> implements Deque<E>, Serializable
一个基于链表的无界双向队列。跨多个线程安全执行并发插入、删除和访问操作。当许多线程将共享对公共集合的访问权限时,ConcurrentLinkedDeque是一个合适的选择。。像大多数其他并行采集的实现,与大多数其他并发集合实现一样,此类不允许使用null元素。迭代器和spliterators是weakly consistent。
请注意,与大多数集合不同,size方法不是常数时间操作。由于这些数据的异步性质,确定当前元素数需要遍历元素,因此如果在遍历期间修改此集合,则可能会报告不准确的结果。此外,大容量操作
addAll
,removeAll
,retainAll
,containsAll
,equals
,和toArray
不保证是自动执行。例如,与addAll操作同时运行的迭代器可能只查看一些添加的元素。这个类和它的迭代器实现了Deque和Iterator接口的所有的可选方法。
内存一致性效果:内存一致性影响:与其他并发集合一样,在将对象入ConcurrentLinkedDeque线程中的操作发生在从另一个线程中对这个ConcurrentLinkedQue访问或删除该元素的操作之前。
常量、变量、静态内部类
private transient volatile Node<E> head;
//头节点
private transient volatile Node<E> head;
//尾节点
private transient volatile Node<E> tail;
//前一个结点静态变量和下一个节点静态变量
private static final Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR;
@SuppressWarnings("unchecked")
Node<E> prevTerminator() {
return (Node<E>) PREV_TERMINATOR;
}
@SuppressWarnings("unchecked")
Node<E> nextTerminator() {
return (Node<E>) NEXT_TERMINATOR;
}
static final class Node<E> {
volatile Node<E> prev;
volatile E item;
volatile Node<E> next;
Node() { // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
}
/**
* Constructs a new node. Uses relaxed write because item can
* only be seen after publication via casNext or casPrev.
*/
Node(E item) {
UNSAFE.putObject(this, itemOffset, item);
}
boolean casItem(E cmp, E val) {
return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
}
void lazySetNext(Node<E> val) {
UNSAFE.putOrderedObject(this, nextOffset, val);
}
boolean casNext(Node<E> cmp, Node<E> val) {
return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
void lazySetPrev(Node<E> val) {
UNSAFE.putOrderedObject(this, prevOffset, val);
}
boolean casPrev(Node<E> cmp, Node<E> val) {
return UNSAFE.compareAndSwapObject(this, prevOffset, cmp, val);
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long prevOffset;
private static final long itemOffset;
private static final long nextOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> k = Node.class;
prevOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("prev"));
itemOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("item"));
nextOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("next"));
} catch (Exception e) {
throw new Error(e);
}
}
}
相较于ConcurrentLinkedQueue Node多了prev, 和用cas操作prev的几个方法的几个方法
队列中常用的方法
add
//头部插入
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
checkNotNull(e);
final Node<E> newNode = new Node<E>(e);
restartFromHead:
for (;;)
for (Node<E> h = head, p = h, q;;) {
if ((q = p.prev) != null &&
(q = (p = q).prev) != null)
// Check for head updates every other hop.
// If p == q, we are sure to follow head instead.
p = (h != (h = head)) ? h : q;
else if (p.next == p) // PREV_TERMINATOR
continue restartFromHead;
else {
// p is first node
newNode.lazySetNext(p); // CAS piggyback
if (p.casPrev(null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this deque,
// and for newNode to become "live".
if (p != h) // hop two nodes at a time
casHead(h, newNode); // Failure is OK.
return;
}
// Lost CAS race to another thread; re-read prev
}
}
}
//尾部插入
public void addLast(E e) {
linkLast(e);
}
private void linkLast(E e) {
checkNotNull(e);
final Node<E> newNode = new Node<E>(e);
restartFromTail:
for (;;)
for (Node<E> t = tail, p = t, q;;) {
if ((q = p.next) != null &&
(q = (p = q).next) != null)
// Check for tail updates every other hop.
// If p == q, we are sure to follow tail instead.
p = (t != (t = tail)) ? t : q;
else if (p.prev == p) // NEXT_TERMINATOR
continue restartFromTail;
else {
// p is last node
newNode.lazySetPrev(p); // CAS piggyback
if (p.casNext(null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this deque,
// and for newNode to become "live".
if (p != t) // hop two nodes at a time
casTail(t, newNode); // Failure is OK.
return;
}
// Lost CAS race to another thread; re-read next
}
}
}
public boolean add(E e) {
return offerLast(e);
}
offer
public boolean offerLast(E e) {
linkLast(e);
return true;
}
public boolean offerFirst(E e) {
linkFirst(e);
return true;
}
public boolean offer(E e) {
return offerLast(e);
}
通过add和offer我们可以更加确信一开始的猜想,如果想要理解linkFirst和linkLast方法内的内容,请参考上一章ConcurrentLinkedQueue的介绍
remove
public E remove() { return removeFirst(); }
public E removeFirst() {
return screenNullResult(pollFirst());
}
public E removeLast() {
return screenNullResult(pollLast());
}
private E screenNullResult(E v) {
if (v == null)
throw new NoSuchElementException();
return v;
}
//remove调用的poll
poll
public E pollFirst() {
for (Node<E> p = first(); p != null; p = succ(p)) {
E item = p.item;
if (item != null && p.casItem(item, null)) {
unlink(p);
return item;
}
}
return null;
}
Node<E> first() {
restartFromHead:
for (;;)
for (Node<E> h = head, p = h, q;;) {
if ((q = p.prev) != null &&
(q = (p = q).prev) != null)
// Check for head updates every other hop.
// If p == q, we are sure to follow head instead.
p = (h != (h = head)) ? h : q;
else if (p == h
// It is possible that p is PREV_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
|| casHead(h, p))
return p;
else
continue restartFromHead;
}
}
final Node<E> succ(Node<E> p) {
// TODO: should we skip deleted nodes here?
Node<E> q = p.next;
return (p == q) ? first() : q;
}
public E pollLast() {
for (Node<E> p = last(); p != null; p = pred(p)) {
E item = p.item;
if (item != null && p.casItem(item, null)) {
unlink(p);
return item;
}
}
return null;
}
Node<E> last() {
restartFromTail:
for (;;)
for (Node<E> t = tail, p = t, q;;) {
if ((q = p.next) != null &&
(q = (p = q).next) != null)
// Check for tail updates every other hop.
// If p == q, we are sure to follow tail instead.
p = (t != (t = tail)) ? t : q;
else if (p == t
// It is possible that p is NEXT_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
|| casTail(t, p))
return p;
else
continue restartFromTail;
}
}
final Node<E> pred(Node<E> p) {
Node<E> q = p.prev;
return (p == q) ? last() : q;
}
//细节请参考上一章ConcurrentLinkedQueue
peek
public E peek() { return peekFirst(); }
public E peekFirst() {
for (Node<E> p = first(); p != null; p = succ(p)) {
E item = p.item;
if (item != null)
return item;
}
return null;
}
public E peekLast() {
for (Node<E> p = last(); p != null; p = pred(p)) {
E item = p.item;
if (item != null)
return item;
}
return null;
}
element
public E element() { return getFirst(); }
public E getFirst() {
return screenNullResult(peekFirst());
}
结论
1. ConcurrentLinkedDeQue是通过Node来存储元素的
2. 数据结构是双向链表, 所以是双向队列
3、 ConcurrentLinkedQueue 是通过Unsafe的cas乐观锁和volitile修饰head和tail来实现线程安全的