目录
7、iterator / descendingIterator
ConcurrentLinkedDeque表示一个无固定容量的,线程安全的,基于CAS而非ReentrantLock互斥锁实现的双端队列,其实现方式跟ConcurrentLinkedQueue类似,本篇博客就详细探讨该类的实现细节。
1、定义
ConcurrentLinkedDeque的类继承关系如下:
只实现了Deque接口,未实现BlockingDeque接口,相关方法的功能可以参考《Java8 LinkedBlockingDeque 源码解析》。
该类包含的实例属性如下:
//链表头
private transient volatile Node<E> head;
//链表尾
private transient volatile Node<E> tail;
private static final int HOPS = 2;
包含的静态属性通过static代码块初始化,如下:
其中PREV_TERMINATOR和NEXT_TERMINATOR都是两个静态常量,Node是一个静态的内部类,实现如下:
static final class Node<E> {
volatile Node<E> prev; //前一个节点
volatile E item; //关联的元素
volatile Node<E> next; //下一个节点
Node() { // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
}
Node(E item) {
UNSAFE.putObject(this, itemOffset, item);
}
//compareAndSwapObject和putOrderedObject都会保证修改对其CPU立即可见
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);
}
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);
}
}
}
2、构造方法
public ConcurrentLinkedDeque() {
//初始化head和tail属性
head = tail = new Node<E>(null);
}
public ConcurrentLinkedDeque(Collection<? extends E> c) {
// Copy c into a private chain of Nodes
Node<E> h = null, t = null;
//遍历集合c
for (E e : c) {
checkNotNull(e);
Node<E> newNode = new Node<E>(e);
if (h == null)
h = t = newNode; //链表未初始化
else {
//插入到tail的后面
t.lazySetNext(newNode);
newNode.lazySetPrev(t);
t = newNode;
}
}
initHeadTail(h, t);
}
private void initHeadTail(Node<E> h, Node<E> t) {
if (h == t) {
if (h == null) //两个都是空
h = t = new Node<E>(null);
else {
//两个非空,即此时链表中只有一个元素,构建一个空节点作为tail
Node<E> newNode = new Node<E>(null);
t.lazySetNext(newNode);
newNode.lazySetPrev(t);
t = newNode;
}
}
head = h;
tail = t;
}
3、add / offer / addAll
add和offer类方法的核心就是linkFirst和linkLast方法。
public boolean add(E e) {
return offerLast(e);
}
public void addFirst(E e) {
linkFirst(e);
}
public void addLast(E e) {
linkLast(e);
}
public boolean offer(E e) {
return offerLast(e);
}
public boolean offerFirst(E e) {
linkFirst(e);
return true;
}
public boolean offerLast(E e) {
linkLast(e);
return true;
}
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 && //head前面两个节点都非空
(q = (p = q).prev) != null)
//如果head节点发生变更,p等于新的head节点,否则p等于q,然后开始下一次for循环,直到有一个节点的prev为null,即找到链表最前面的一个节点
p = (h != (h = head)) ? h : q;
else if (p.next == p) // 这个节点原来是head,即将被移除,重新读取head
continue restartFromHead;
else {
//第一个的if条件不成立,p的prev为null,p就是链表中第一个节点
newNode.lazySetNext(p); // CAS piggyback
if (p.casPrev(null, newNode)) {
//如果cas修改prev成功
if (p != h) //如果p不等于head则修改head,当p等于head的前一个节点时p就不等于head
//如果等于则不修改,下一次调用此方法时再修改,相当于节省了一次casHead调用
//cas修改head,如果修改失败,则表示其他线程修改了head,其他线程插入节点只能插入到nowNode的后面,所以只要有一个线程修改成功即可
casHead(h, newNode);
return;
}