publicbooleanoffer(E e){ // 检查是否为null,会抛出空指针 checkNotNull(e); // 构造Node节点 final Node<E> newNode = new Node<E>(e); // 从尾节点进行插入,循环直到成功为止 for (Node<E> t = tail, p = t;;) { Node<E> q = p.next; // 如果q为null,说明当前p是尾节点,尝试加入到队尾,如果加入失败,表示其他线程已经修改了p的指向 if (q == null) { // 初始时,head、tail 都指向同一个 item 为 null 的节点 // 使用CAS操作设置p节点的next节点,但是没有更新尾节点 // 如果有多线程操作,会导致第一次CAS操作失败,再次执行for循环 if (p.casNext(null, newNode)) { // CAS操作成功,新增节点被放入到链表中 // p!=t,表示有多线程操作,导致第一次cas操作没有成功,此次不是第一次cas操作,此时在进行设置尾节点 if (p != t) // hop two nodes at a time // 设置当前尾节点为新插入的节点 casTail(t, newNode); // Failure is OK. returntrue; } // Lost CAS race to another thread; re-read next } elseif (p == q) // 多线程操作时,由于poll操作移除元素后可能会把head变成自引用(环形链表),此时head的next节点也是head,所以需要重新找到新的head // 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. // 寻找尾节点,找到当前的尾节点之后,再次执行for循环 p = (p != t && t != (t = tail)) ? t : q; } }
public E poll(){ restartFromHead: for (;;) { // 从头节点开始遍历 for (Node<E> h = head, p = h, q;;) { // 保存当前节点 E item = p.item; // 当前节点有值,并且使用CAS操作将当前节点变为null成功 if (item != null && p.casItem(item, null)) { // Successful CAS is the linearization point // for item to be removed from this queue. // CAS操作成功,则标记当前节点从链表中移除 // 只有多线程操作时,使得第一次p!=h时才会设置头节点为p if (p != h) // hop two nodes at a time updateHead(h, ((q = p.next) != null) ? q : p); return item; } // 当前队列为空 elseif ((q = p.next) == null) { updateHead(h, p); returnnull; } // 多线程同时操作时才会出现该情况,当前节点自引用,需要重新寻找新的队列头节点 elseif (p == q) continue restartFromHead; else// 多线程操作时,会导致第一次判断时item为null,且此时已经有了新插入的节点了,需要重新指定头节点 p = q; } } }
peek方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// 与poll方法类似,只是少了cas操作来清空头节点的值 public E peek(){ restartFromHead: for (;;) { for (Node<E> h = head, p = h, q;;) { E item = p.item; if (item != null || (q = p.next) == null) { updateHead(h, p); return item; } elseif (p == q) continue restartFromHead; else p = q; } } }
publicbooleanremove(Object o){ if (o != null) { Node<E> next, pred = null; for (Node<E> p = first(); p != null; pred = p, p = next) { boolean removed = false; E item = p.item; if (item != null) { if (!o.equals(item)) { next = succ(p); continue; } // 使用cas操作来进行remove removed = p.casItem(item, null); }
next = succ(p); // 如果有前驱节点,并且next不为空,则需要将这两个连接起来 if (pred != null && next != null) // unlink pred.casNext(p, next); if (removed) returntrue; } } returnfalse; }
head和tail的更新时机
tail 更新时机:tail 节点不总是尾节点,如果 tail 节点的 next 节点不为空,则将入队节点设置成 tail 节点;如果 tail 节点的 next 节点为空,则只入队不更新尾节点。
head 更新时机:并不是每次出队时都更新 head 节点,当 head 节点里有元素时,直接弹出 head 节点里的元素,而不会更新 head 节点;只有当 head 节点里没有元素时,出队操作才会更新 head 节点。
head 和 tail 的更新总是间隔了一个,是为了减少CAS的更新操作,如果大量的入队操作,每次都要执行 CAS 进行 tail 的更新,汇总起来对性能也会是大大的损耗。如果能减少 CAS 更新的操作,无疑可以大大提升入队的操作效率