由于LinkedBlockingDeque作为双端队列的实现,采用了单锁的保守策略使其不利于多线程并发情况下的使用,故ConcurrentLinkedDeque应运而生,它是一种基于链表的无界的同时支持FIFO、LIFO的非阻塞并发双端队列,当许多线程共享对公共集合的访问时,ConcurrentLinkedDeque是一个合适的选择,类比ConcurrentLinkedQueue是针对LinkedBlockingQueue对高并发情况的一种解决方案,ConcurrentLinkedDeque也是同样的地位,都是采用 CAS来替代加锁,甚至ConcurrentLinkedDeque再实现上也与ConcurrentLinkedQueue有很多相似的地方,其中最值得提及的就是,它采用了与ConcurrentLinkedQueue一样的松弛阀值设计(松弛阀值都是1),即head、tail并不总是指向队列的第一个、最后一个节点,而是保持head/tail距离第一个/最后一个节点的距离不超过1个节点的距离,从而减少了更新head/tail指针的CAS次数。Java Doc指出理解ConcurrentLinkedQueue的实现是理解该类实现的先决条件,所以最好先理解了ConcurrentLinkedQueue再来理解该类。

ConcurrentLinkedDeque另外还使用了两种方法来减少volatile写的次数:一是使用单次CAS操作来一次性使多次连续的CAS生效;二是将对同一块内存地址的volatile写与普通写混合。它的节点类与LinkedBlockingDeque的属性一致都是数据item、prev、next,只是多了一些CAS操作方法。与ConcurrentLinkedQueue一样,只有那些数据item不为空的节点才被认为是活动的节点,当将item置为null时,意味着从队列中逻辑删除掉了。

与LinkedBlockingDeque一样,任何时候,队列的第一个节点"first"的前驱prev为null,队列的最后一个节点"tail"的next后继为null。“first”和“last”节点可能是活动的,也可能不是活动的。“first”和“last”节点总是相互可达的。通过将第一个或最后一个节点的空前驱或后继CAS引用到包含指定元素的新节点,实现原子性地添加一个新元素,从而元素的节点在那时原子性地变成“活动的”,如果一个节点是活动的(item不为null)或者它是first/last节点,我们都称为是有效节点。ConcurrentLinkedDeque同样采用了“自链接(p.prev = p或p.next = p)”的方式使节点断开与队列的链接,有效活动节点不会有自链接的情况。

前面说了ConcurrentLinkedDeque有两个不总是指向第一个/最后一个节点的head、tail指针,所以它并没有像LinkedBlockingDeque那样设计first、tail属性,但是first、tail总是可以通过head、tail在O(1)时间内找到。

ConcurrentLinkedDeque删除节点分三个阶段:

  1. logical deletion(逻辑删除):通过CAS将数据item置为null,使该节点满足解除链接(unlinking)的条件。
  2. unlinking(解除链接):该阶段使队列中的活动节点无法到达该节点,但是保留该节点到队列中活动节点的链接,从而最终可由GC回收。此阶段典型的就是被迭代器使用的时候,使迭代器可以继续往下迭代。
  3. gc-unlinking:该阶段进一步解除被删除节点到队列中活动节点的链接,使其更容易被GC回收,通过让节点自链接或链接到终止节点(PREV_TERMINATOR 或 NEXT_TERMINATOR)来实现。这一步是为了使数据结构保持GC健壮性(gc-robust),消除使用保守式GC(conservative GC,目前已经很少使用)对内存无限期滞留的风险,并提高了分代GC的性能。

 由于删除节点的第二、三阶段都不是保证数据正确性必须的,仅仅是对迭代器与内存的优化,故适当的减少这些操作的次数对性能是一种提高。所以ConcurrentLinkedDeque不仅设计了同ConcurrentLinkedQueue一样针对head、tail节点的松弛阈值,而且还提供了针对解除删除节点链接的阈值HOPS,也就是只有当逻辑删除的节点个数达到一定数量才会触发unlinking 和gc-unlinking,这样也是对性能的一种优化。

同ConcurrentLinkedQueue一样,ConcurrentLinkedDeque也对head、tail设定了如下的一些不变与可变性约束:

head/tail的不变性:

  1. 第一个节点总是可从head通过prev链接在O(1)时间复杂度内访问到。
  2. 最后一个节点总是可以从tail通过next链接在O(1)时间复杂度内访问到。
  3. 所有活动节点(item不为null)都可以从第一个节点通过succ()访问。
  4. 所有活动节点(item不为null)都可以从最后一个节点通过pred()访问。
  5. head和tail都不会为null。
  6. head节点的next不会指向自身形成自连接。
  7. head/tail不会是GC-unlinked节点(但它可能是unlink节点)。

head/tail的可变性:

  1. head、tail的数据item可以为null,也可以不为null。
  2. head可能无法从第一个或最后一个节点或从tail到达。
  3. tail可能无法从第一个或最后一个节点或从head到达。

下面开始分析ConcurrentLinkedDeque的源码,ConcurrentLinkedDeque和ConcurrentLinkedQueue并没有继承相应的BlockingQueue/BlockingQueue,容量又是无界的,所以不存在阻塞方法。

源码解析

 首先看它的一些基础字段、节点内部类以及构造方法:

  1  /**
  2  * A node from which the first node on list (that is, the unique node p with p.prev == null && p.next != p) can be reached in O(1) time.
  3    可以在O(1)时间内从列表中的第一个节点到达的节点(即,具有p.prev == null && p.next!= p的唯一节点p)。
  4    
  5  * Invariants: 不变性
  6  * - the first node is always O(1) reachable from head via prev links 第一个节点总是可从head通过prev链接在O(1)时间内访问到
  7  * - all live nodes are reachable from the first node via succ() 所有活动节点都可以从第一个节点通过succ()访问
  8  * - head != null                                                  head不为空
  9  * - (tmp = head).next != tmp || tmp != head  
 10  * - head is never gc-unlinked (but may be unlinked) 。head永远不会gc-unlinked(但可能是unlinked)
 11  
 12  * Non-invariants: 可变性
 13  * - head.item may or may not be null                                           head 的数据项可以为空
 14  * - head may not be reachable from the first or last node, or from tail 。 head 可能无法从第一个或最后一个节点或从tail到达。
 15  */
 16 private transient volatile Node<E> head;
 17 
 18 /**
 19  * A node from which the last node on list (that is, the unique node p
 20  * with p.next == null && p.prev != p) can be reached in O(1) time.
 21    可以在O(1)时间内从列表中的最后一个节点到达的节点(即具有p.next == null && p.prev!= p的唯一节点p)。
 22 
 23  * Invariants: 不变性
 24  * - the last node is always O(1) reachable from tail via next links。最后一个节点始终可以通过下一个链接从tail访问在O(1)时间内访问到
 25  * - all live nodes are reachable from the last node via pred() 。所有活动节点都可以从最后一个节点通过pred()访问
 26  * - tail != null                                                            tail不为空
 27  * - tail is never gc-unlinked (but may be unlinked)                tail永远不会gc-unlinked(但可能是unlinked)
 28  
 29  * Non-invariants: 可变性
 30  * - tail.item may or may not be null                                            tail的数据项可以为空
 31  * - tail may not be reachable from the first or last node, or from head      tail可能无法从第一个或最后一个节点或从head访问到。
 32  */
 33 private transient volatile Node<E> tail;
 34 
 35 /**指示出队节点的终结节点*/
 36 private static final Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR;
 37 
 38 
 39 @SuppressWarnings("unchecked")
 40 Node<E> prevTerminator() { //从对头出队节点的前向终结节点
 41     return (Node<E>) PREV_TERMINATOR;
 42 }
 43 
 44 @SuppressWarnings("unchecked")
 45 Node<E> nextTerminator() { //从对尾出队节点的后继终结节点
 46     return (Node<E>) NEXT_TERMINATOR;
 47 }
 48 
 49 static final class Node<E> {
 50     volatile Node<E> prev;
 51     volatile E item;
 52     volatile Node<E> next;
 53 
 54     Node() {  // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
 55     }
 56 
 57     /**
 58      * Constructs a new node.  Uses relaxed write because item can
 59      * only be seen after publication via casNext or casPrev.
 60      */
 61     Node(E item) {
 62         UNSAFE.putObject(this, itemOffset, item);
 63     }
 64 
 65     boolean casItem(E cmp, E val) {
 66         return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
 67     }
 68 
 69     void lazySetNext(Node<E> val) {
 70         UNSAFE.putOrderedObject(this, nextOffset, val);
 71     }
 72 
 73     boolean casNext(Node<E> cmp, Node<E> val) {
 74         return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
 75     }
 76 
 77     void lazySetPrev(Node<E> val) {
 78         UNSAFE.putOrderedObject(this, prevOffset, val);
 79     }
 80 
 81     boolean casPrev(Node<E> cmp, Node<E> val) {
 82         return UNSAFE.compareAndSwapObject(this, prevOffset, cmp, val);
 83     }
 84 
 85     // Unsafe mechanics
 86     private static final sun.misc.Unsafe UNSAFE;
 87     private static final long prevOffset;
 88     private static final long itemOffset;
 89     private static final long nextOffset;
 90 
 91     static {
 92         try {
 93             UNSAFE = sun.misc.Unsafe.getUnsafe();
 94             Class<?> k = Node.class;
 95             prevOffset = UNSAFE.objectFieldOffset
 96                 (k.getDeclaredField("prev"));
 97             itemOffset = UNSAFE.objectFieldOffset
 98                 (k.getDeclaredField("item"));
 99             nextOffset = UNSAFE.objectFieldOffset
100                 (k.getDeclaredField("next"));
101         } catch (Exception e) {
102             throw new Error(e);
103         }
104     }
105 }
106 
107 //针对被删除节点进行unlinking/GC-unlinking的阈值
108 private static final int HOPS = 2;
109 
110 private boolean casHead(Node<E> cmp, Node<E> val) {
111     return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
112 }
113 
114 private boolean casTail(Node<E> cmp, Node<E> val) {
115     return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
116 }
117 
118 // Unsafe mechanics
119 private static final sun.misc.Unsafe UNSAFE;
120 private static final long headOffset;
121 private static final long tailOffset;
122 static {
123     PREV_TERMINATOR = new Node<Object>();
124     PREV_TERMINATOR.next = PREV_TERMINATOR;
125     NEXT_TERMINATOR = new Node<Object>();
126     NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
127     try {
128         UNSAFE = sun.misc.Unsafe.getUnsafe();
129         Class<?> k = ConcurrentLinkedDeque.class;
130         headOffset = UNSAFE.objectFieldOffset
131             (k.getDeclaredField("head"));
132         tailOffset = UNSAFE.objectFieldOffset
133             (k.getDeclaredField("tail"));
134     } catch (Exception e) {
135         throw new Error(e);
136     }
137 }
138 
139 /**
140  * Constructs an empty deque. 默认构造方法,head、tail都指向同一个item为null的节点
141  */
142 public ConcurrentLinkedDeque() {
143     head = tail = new Node<E>(null);
144 }
145 
146 /**
147  * Constructs a deque initially containing the elements of
148  * the given collection, added in traversal order of the
149  * collection's iterator.
150  *
151  * @param c the collection of elements to initially contain
152  * @throws NullPointerException if the specified collection or any
153  *         of its elements are null
154  */
155 public ConcurrentLinkedDeque(Collection<? extends E> c) {
156     // Copy c into a private chain of Nodes
157     Node<E> h = null, t = null;
158     for (E e : c) {
159         checkNotNull(e);
160         Node<E> newNode = new Node<E>(e);
161         if (h == null)
162             h = t = newNode;
163         else {
164             t.lazySetNext(newNode);
165             newNode.lazySetPrev(t);
166             t = newNode;
167         }
168     }
169     initHeadTail(h, t);
170 }
171 
172 /**
173  * Initializes head and tail, ensuring invariants hold.
174  * 初始化head和tail,确保它们的不变性
175  */
176 private void initHeadTail(Node<E> h, Node<E> t) {
177     if (h == t) { //队列为空,或者只有一个元素
178         if (h == null)
179             h = t = new Node<E>(null);//队列为空,head、tail都指向同一个item为null的节点
180         else { 
181             // 只有一个元素,重新构造一个节点指向tail,避免head、tail都指向同一个非null节点
182             // Avoid edge case of a single Node with non-null item.
183             Node<E> newNode = new Node<E>(null);
184             t.lazySetNext(newNode);
185             newNode.lazySetPrev(t);
186             t = newNode;
187         }
188     }
189     head = h;
190     tail = t;
191 }
View Code

相关文章:

  • 2021-12-26
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-05-11
  • 2021-12-21
  • 2021-11-20
  • 2022-12-23
猜你喜欢
  • 2021-08-14
  • 2022-01-11
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案