Re: why ConcurrentLinkedQueue#addAll need set tail twice?
Martin Buchholz via Concurrency-interest <[email protected]> Thu, 23 Jul 2020 17:45:26 -0700
| Newsgroups | gmane.comp.java.jsr.166-concurrency |
|---|---|
| Message-ID | <CA+kOe097XwxLxMGE-XWc8nh7G76dtLgG=VUvzGXriRp3XnkH5Q@mail.gmail.com> |
* - There is exactly one (last) Node with a null next reference,
* which is CASed when enqueueing. This last Node can be
* reached in O(1) time from tail, but tail is merely an
* optimization - it can always be reached in O(N) time from
* head as well.
On Thu, Jul 23, 2020 at 6:41 AM Liu via Concurrency-interest
<[email protected]> wrote:
>
> In JDK8's ConcurrentLinkedQueue, there is an addAll function, and it will set tail twice, why?
>
> public boolean addAll(Collection<? extends E> c) {
> if (c == this)
> // As historically specified in AbstractQueue#addAll
> throw new IllegalArgumentException();
>
> // Copy c into a private chain of Nodes
> Node<E> beginningOfTheEnd = null, last = null;
> for (E e : c) {
> checkNotNull(e);
> Node<E> newNode = new Node<E>(e);
> if (beginningOfTheEnd == null)
> beginningOfTheEnd = last = newNode;
> else {
> last.lazySetNext(newNode);
> last = newNode;
> }
> }
> if (beginningOfTheEnd == null)
> return false;
>
> // Atomically append the chain at the tail of this collection
> for (Node<E> t = tail, p = t;;) {
> Node<E> q = p.next;
> if (q == null) {
> // p is last node
> if (p.casNext(null, beginningOfTheEnd)) {
> // Successful CAS is the linearization point
> // for all elements to be added to this queue.
> if (!casTail(t, last)) { // first set tail
> // Try a little harder to update tail,
> // since we may be adding many elements.
> t = tail;
> if (last.next == null)
> casTail(t, last); // second set tail
> }
> return true;
> }
> // Lost CAS race to another thread; re-read next
> }
> else if (p == q)
> // We have fallen off list. If tail is unchanged, it
> // will also be off-list, in which case we need to
> // jump to head, from which all live nodes are always
> // reachable. Else the new tail is a better bet.
> p = (t != (t = tail)) ? t : head;
> else
> // Check for tail updates after two hops.
> p = (p != t && t != (t = tail)) ? t : q;
> }
> }
>
>
> I don't quite understand, I just think the second set operation is not necessary.
> --------------------------------------------------------------------------------
> Regards
> Liu
> _______________________________________________
> Concurrency-interest mailing list
> [email protected]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
_______________________________________________
Concurrency-interest mailing list
[email protected]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest