The source code of this article is based on JDK13

## ConcurrentLinkedDeque

### Official annotation translation

An unbounded, concurrent, double ended queue is implemented using a linked list. Concurrent write, remove, and access operations between multiple threads can ensure security. When many threads share a common set, ConcurrentLinkedDeque is a good choice. Like other concurrent sets, this class does not accept null elements

Iterators are weakly consistent

It should be noted that, unlike most other collections, the size method is not a constant time operation. Because of the asynchronous nature of the queue, counting the current elements requires traversing all elements. Therefore, if other threads are changing, the size method may return inaccurate numbers

Batch operations do not guarantee atomicity, such as addAll. When foreach and addAll run together, foreach may only observe some elements

This class and its Iterator implement all the optional methods of Queue and Iterator

### Source code

#### definition

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

A two - terminal queue

#### Internal linked list node

static final class Node<E> { volatile Node<E> prev; volatile E item; volatile Node<E> next; }

The pointer of the front and back nodes and the element of the current node

#### attribute

private transient volatile Node<E> head; private transient volatile Node<E> tail;

Saved head and tail nodes

#### Construction method

public ConcurrentLinkedDeque() { head = tail = new Node<E>(); } public ConcurrentLinkedDeque(Collection<? extends E> c) { // Copy c into a private chain of Nodes Node<E> h = null, t = null; for (E e : c) { Node<E> newNode = newNode(Objects.requireNonNull(e)); if (h == null) h = t = newNode; else { NEXT.set(t, newNode); PREV.set(newNode, t); t = newNode; } } initHeadTail(h, t); }

Two construction methods, one to construct an empty queue and one to initialize a given set into the queue

#### Team entry method

public void addFirst(E e) { linkFirst(e); } public void addLast(E e) { linkLast(e); } public boolean offerFirst(E e) { linkFirst(e); return true; } public boolean offerLast(E e) { linkLast(e); return true; }

Support the addition of queue head and tail, specifically calling linkFirst and linkLast

- linkFirst

private void linkFirst(E e) { // Create current node final Node<E> newNode = newNode(Objects.requireNonNull(e)); restartFromHead: for (;;) for (Node<E> h = head, p = h, q;;) { // If the front node of the node is not empty, update the p node 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; // Node p is out of the queue and starts from scratch else if (p.next == p) // PREV_TERMINATOR continue restartFromHead; else { // p is first node // Sets the current node as the first NEXT.set(newNode, p); // CAS piggyback // cas updates the related attributes, the pre attributes of the original header node, and the new header node if (PREV.compareAndSet(p, 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; failure is OK HEAD.weakCompareAndSet(this, h, newNode); return; } // Lost CAS race to another thread; re-read prev } } }

Set the current node as the first node, which is realized by CAS + spin. When it is found that the existing head node is out of the queue, find the head node again

- linkLast

The link is a node, which is consistent with the head node

private void linkLast(E e) { final Node<E> newNode = newNode(Objects.requireNonNull(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 PREV.set(newNode, p); // CAS piggyback if (NEXT.compareAndSet(p, 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; failure is OK TAIL.weakCompareAndSet(this, t, newNode); return; } // Lost CAS race to another thread; re-read next } } }

#### Out of line operation

public E pollFirst() { restart: for (;;) { for (Node<E> first = first(), p = first;;) { // Queue head node, cas change attribute final E item; if ((item = p.item) != null) { // recheck for linearizability if (first.prev != null) continue restart; if (ITEM.compareAndSet(p, item, null)) { unlink(p); return item; } } // Out of line, start again if (p == (p = p.next)) continue restart; // p is empty, the queue is empty, and null is returned if (p == null) { if (first.prev != null) continue restart; return null; } } } } public E pollLast() { restart: for (;;) { for (Node<E> last = last(), p = last;;) { final E item; if ((item = p.item) != null) { // recheck for linearizability if (last.next != null) continue restart; if (ITEM.compareAndSet(p, item, null)) { unlink(p); return item; } } if (p == (p = p.prev)) continue restart; if (p == null) { if (last.next != null) continue restart; return null; } } } }

Corresponding to joining the team, pop up the head or tail of the team. The idea is the same

#### Normal queue operation

Double ended queues can provide queue in and queue out operations like ordinary queues. At this time, they are a FIFO queue, that is, the queue in is added to the tail of the queue, and the queue out obtains elements from the head of the queue

#### summary

Consistent with the idea of concurrent linked queue, it is implemented by CAS + spin. It only provides the method related to double ended queue

## Reference articles

End.

## Contact me

Finally, welcome to my personal official account, Yan Yan ten, which will update many learning notes from the backend engineers. I also welcome direct official account or personal mail or email to contact me.

The above are all personal thoughts. If there are any mistakes, please correct them in the comment area.

Welcome to reprint, please sign and keep the original link.

Contact email: huyanshi2580@gmail.com

For more study notes, see personal blog or WeChat official account, Yan Yan ten > > Huyan ten