数据结构 - ConcurrentLinkedDeque 非阻塞双向队列

简介

ConcurrentLinkedDeque是线程安全的非阻塞队列,内部结构跟LinkedBlockingQueue一样使用双向链表,最大的区别就是LinkedBlockingDeque使用CSA原则操作,没有用lock。使用它的时候一样需要注意,头节点和尾节点不保证一定是头和尾。

ConcurrentLinkedDeque类

public class ConcurrentLinkedDeque<E>
        extends AbstractCollection<E>
        implements Deque<E>, java.io.Serializable

继承AbstractCollection,实现Deque接口

重要内部类Node

static final class Node<E>

Node 属性

// 前一个节点
volatile Node<E> prev;
// 当前节点元素
volatile E item;
// 后一个节点
volatile Node<E> next;
// 操作内存不安全类
private static final sun.misc.Unsafe UNSAFE;
// 前一个节点偏移量
private static final long prevOffset;
// 当前元素偏移量
private static final long itemOffset;
// 下一个节点偏移量
private static final long nextOffset;

Node 初始化内存操作

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);
    }
}

Node 构造函数

Node() {
}
Node(E item) {
    UNSAFE.putObject(this, itemOffset, item);
}

Node 方法

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,看Node方法还是很简单的。

ConcurrentLinkedDeque 属性

// 头节点
private transient volatile Node<E> head;
// 尾节点
private transient volatile Node<E> tail;
// 终止节点
private static final Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR;
// 阈值
private static final int HOPS = 2;
// 内存操作不安全类
private static final sun.misc.Unsafe UNSAFE;
// 头节点偏移量
private static final long headOffset;
// 尾节点偏移量
private static final long tailOffset;

ConcurrentLinkedDeque 构造函数

public ConcurrentLinkedDeque() {
    // 初始化一个空元素节点
    head = tail = new Node<E>(null);
}
public ConcurrentLinkedDeque(Collection<? extends E> c) {
    Node<E> h = null, t = null;
    // 便利线性集合
    for (E e : c) {
        // 检查元素是否为空
        checkNotNull(e);
        // 构建节点
        Node<E> newNode = new Node<E>(e);
        // 头节点为空设置头节点,不为空设置下级节点
        if (h == null)
            h = t = newNode;
        else {
            t.lazySetNext(newNode);
            newNode.lazySetPrev(t);
            t = newNode;
        }
    }
    // 设计尾节点
    initHeadTail(h, t);
}

ConcurrentLinkedDeque 基础方法

更新头节点

private final void updateHead() {
    Node<E> h, p, q;
    restartFromHead:
    // 头节点元素为空,上一个节点不为空
    while ((h = head).item == null && (p = h.prev) != null) {
        for (;;) {
            // 头节点上一个节点为空或上上节点为空
            if ((q = p.prev) == null ||
                    (q = (p = q).prev) == null) {
                // 跟新p为头节点
                if (casHead(h, p))
                    return;
                else
                    continue restartFromHead;
            }
            // 头节点改变了重新设置
            else if (h != head)
                continue restartFromHead;
            else
                p = q;
        }
    }
}

更新尾节点

private final void updateTail() {
    Node<E> t, p, q;
    restartFromTail:
    // 尾节点为空或尾节点下一个节点为空
    while ((t = tail).item == null && (p = t.next) != null) {
        for (;;) {
            // 尾节点下一个为空,或下下一个为空
            if ((q = p.next) == null ||
                    (q = (p = q).next) == null) {
                // 设置尾节点
                if (casTail(t, p))
                    return;
                else
                    continue restartFromTail;
            }
            // 尾节点已经改变重新设置
            else if (t != tail)
                continue restartFromTail;
            else
                p = q;
        }
    }
}

获取头节点

Node<E> first() {
    restartFromHead:
    for (;;)
        // 从头节点开始遍历
        for (Node<E> h = head, p = h, q;;) {
            // 前面还有节点
            if ((q = p.prev) != null &&
                    (q = (p = q).prev) != null)
                // p 前移
                p = (h != (h = head)) ? h : q;
            else if (p == h
                    // 修改头节点
                    || casHead(h, p))
                // 返回头节点
                return p;
            else
                continue restartFromHead;
        }
}

获取尾节点

Node<E> last() {
    restartFromTail:
    for (;;)
        // 从尾节点开始遍历
        for (Node<E> t = tail, p = t, q;;) {
            // 尾节点后还有节点
            if ((q = p.next) != null &&
                    (q = (p = q).next) != null)
                // p 后移
                p = (t != (t = tail)) ? t : q;
            else if (p == t
                    // 更新尾节点
                    || casTail(t, p))
                return p;
            else
                continue restartFromTail;
        }
}

ConcurrentLinkedDeque 添加

public boolean offerFirst(E e) {
    // 调用linkFirst
    linkFirst(e);
    return true;
}
public boolean offerLast(E e) {
    // 调用linkLast
    linkLast(e);
    return true;
}

委托linkFirst、linkLast方法

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)
                // p 节点前移
                p = (h != (h = head)) ? h : q;
            else if (p.next == p) // 头节点移除会自己指向自己
                continue restartFromHead;
            else {
                // 新节点下一个节点设置为p节点
                newNode.lazySetNext(p);
                // 设置p上级节点为新节点
                if (p.casPrev(null, newNode)) {
                    // 后一个线程去更新头节点
                    if (p != h)
                        casHead(h, newNode);
                    return;
                }
            }
        }
}
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)
                // 后移p节点
                p = (t != (t = tail)) ? t : q;
            else if (p.prev == p) // 尾节点移除会自己指向自己
                continue restartFromTail;
            else {
                // 新节点上一个节点设置为p
                newNode.lazySetPrev(p);
                // 设置p的下级节点为新节点
                if (p.casNext(null, newNode)) {
                    // 后一个线程去更新尾节点
                    if (p != t)
                        casTail(t, newNode);
                    return;
                }
            }
        }
}

ConcurrentLinkedDeque 出队

头部出队

public E pollFirst() {
    // 找头节点,然后遍历
    for (Node<E> p = first(); p != null; p = succ(p)) {
        // 获取元素
        E item = p.item;
        // 把当前头元素修改为null
        if (item != null && p.casItem(item, null)) {
            // 从链表中移除
            unlink(p);
            return item;
        }
    }
    return null;
}

尾部出队

public E pollLast() {
    // 找尾节点,然后开始遍历
    for (Node<E> p = last(); p != null; p = pred(p)) {
        // 获取元素
        E item = p.item;
        // 把当前头元素修改为null
        if (item != null && p.casItem(item, null)) {
            // 从链表中移除
            unlink(p);
            return item;
        }
    }
    return null;
}

删除元素

void unlink(Node<E> x) {
    // 获取当前节点上一个下一个节点
    final Node<E> prev = x.prev;
    final Node<E> next = x.next;
    // 上一个节点为空,修改下一个节点为头节点
    if (prev == null) {
        unlinkFirst(x, next);
    } else if (next == null) {
        // 下一个节点为空,修改上一个节点为尾节点
        unlinkLast(x, prev);
    } else {// 能到这说明上下节点不为null
        Node<E> activePred, activeSucc;
        boolean isFirst, isLast;
        int hops = 1;
        // 往前遍历
        for (Node<E> p = prev; ; ++hops) {
            // x上一个节点元素不为空
            // 说明x不是头节点
            if (p.item != null) {
                activePred = p;
                isFirst = false;
                break;
            }
            // x的上上一个节点
            Node<E> q = p.prev;
            // 上上一个节点为空
            if (q == null) {
                // 看一下p是不是已经变成活动节点了
                if (p.next == p)
                    return;
                activePred = p;
                // 设置为头节点
                isFirst = true;
                break;
            }
            // 活动节点自引用
            else if (p == q)
                return;
            else
                // 前移
                p = q;
        }
        // 找下一个节点
        for (Node<E> p = next; ; ++hops) {
            // x下一个节点元素不为空
            // 说明x不是尾节点
            if (p.item != null) {
                activeSucc = p;
                isLast = false;
                break;
            }
            // 找下下一个节点
            Node<E> q = p.next;
            // 下下一个节点为空
            if (q == null) {
                // 看看是否是自引用了
                if (p.prev == p)
                    return;
                activeSucc = p;
                // 设置为尾节点
                isLast = true;
                break;
            }
            // 自引用了
            else if (p == q)
                return;
            else
                // 后移
                p = q;
        }
        // 小于阈值 并且是头节点或者是尾节点直接返回
        if (hops < HOPS && (isFirst | isLast))
            return;
        // 是头节点或尾节点
        if ((isFirst | isLast) &&
                (activePred.next == activeSucc) &&
                (activeSucc.prev == activePred) &&
                (isFirst ? activePred.prev == null : activePred.item != null) &&
                (isLast  ? activeSucc.next == null : activeSucc.item != null)) {
            // 修改头节点或尾节点
            updateHead();
            updateTail(); 
            x.lazySetPrev(isFirst ? prevTerminator() : x);
            x.lazySetNext(isLast  ? nextTerminator() : x);
        }
    }
}

头部删除元素

private void unlinkFirst(Node<E> first, Node<E> next) {
    for (Node<E> o = null, p = next, q;;) {
        // next 的元素不为空或者next 下一个元素为空
        if (p.item != null || (q = p.next) == null) {
            // o不为空,所以第一次不能进来
            if (o != null && p.prev != p && first.casNext(next, p)) {
                skipDeletedPredecessors(p);
                // 修改头节点和尾节点
                if (first.prev == null &&
                        (p.next == null || p.item != null) &&
                        p.prev == first) {
                    updateHead(); 
                    updateTail(); 
                    o.lazySetNext(o);
                    o.lazySetPrev(prevTerminator());
                }
            }
            return;
        }
        else if (p == q)
            return;
        else {
            // 节点后移
            o = p;
            p = q;
        }
    }
}

尾部删除元素

private void unlinkLast(Node<E> last, Node<E> prev) {
    for (Node<E> o = null, p = prev, q;;) {
        // prev 元素不为空或者prev的前一个节点为空
        if (p.item != null || (q = p.prev) == null) {
            // o不为空,一样第一次不能进来
            if (o != null && p.next != p && last.casPrev(prev, p)) {
                skipDeletedSuccessors(p);
                // 修改头和尾
                if (last.next == null &&
                        (p.prev == null || p.item != null) &&
                        p.next == last) {
                    updateHead(); 
                    updateTail(); 
                    o.lazySetPrev(o);
                    o.lazySetNext(nextTerminator());
                }
            }
            return;
        }
        else if (p == q)
            return;
        else {
            // 节点前移
            o = p;
            p = q;
        }
    }
}

ConcurrentLinkedDeque 查询

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;
}

posted @ 2020-04-14 22:27  源码猎人  阅读(230)  评论(0编辑  收藏  举报