|
| 1 | +# ConcurrentLinkedQueue |
| 2 | +* ** 非阻塞**的链表队列 |
| 3 | +* 通过CAS实现无锁非阻塞 |
| 4 | +>基于链接节点的、无界的、线程安全。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部,队列检索操作从队列头部获得元素。当许多线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许 null 元素。 |
| 5 | +
|
| 6 | +## Node |
| 7 | +* ConcurrentLinkedQueue的内部私有类 |
| 8 | +* 使用了通过C++编写的Unsafe类 |
| 9 | +```Java |
| 10 | + private static class Node<E> { |
| 11 | + volatile E item; |
| 12 | + volatile Node<E> next; |
| 13 | + /** |
| 14 | + * Constructs a new node. Uses relaxed write because item can |
| 15 | + * only be seen after publication via casNext. |
| 16 | + */ |
| 17 | + Node(E item) { |
| 18 | + UNSAFE.putObject(this, itemOffset, item); |
| 19 | + } |
| 20 | + boolean casItem(E cmp, E val) { |
| 21 | + return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); |
| 22 | + } |
| 23 | + void lazySetNext(Node<E> val) { |
| 24 | + UNSAFE.putOrderedObject(this, nextOffset, val); |
| 25 | + } |
| 26 | + boolean casNext(Node<E> cmp, Node<E> val) { |
| 27 | + return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); |
| 28 | + } |
| 29 | + // Unsafe mechanics |
| 30 | + private static final sun.misc.Unsafe UNSAFE; |
| 31 | + private static final long itemOffset; |
| 32 | + private static final long nextOffset; |
| 33 | + static { |
| 34 | + try { |
| 35 | + UNSAFE = sun.misc.Unsafe.getUnsafe(); |
| 36 | + Class<?> k = Node.class; |
| 37 | + itemOffset = UNSAFE.objectFieldOffset |
| 38 | + (k.getDeclaredField("item")); |
| 39 | + nextOffset = UNSAFE.objectFieldOffset |
| 40 | + (k.getDeclaredField("next")); |
| 41 | + } catch (Exception e) { |
| 42 | + throw new Error(e); |
| 43 | + } |
| 44 | + } |
| 45 | + } |
| 46 | +``` |
| 47 | + |
| 48 | +## ConcurrentLinkedQueue's API |
| 49 | +* add() 通过offer方法添加元素。 |
| 50 | +```Java |
| 51 | + public boolean add(E e) { |
| 52 | + return offer(e); |
| 53 | + } |
| 54 | +``` |
| 55 | + |
| 56 | +* offer() |
| 57 | +```Java |
| 58 | + public boolean offer(E e) { |
| 59 | + checkNotNull(e); |
| 60 | + final Node<E> newNode = new Node<E>(e); |
| 61 | + |
| 62 | + for (Node<E> t = tail, p = t;;) { |
| 63 | + Node<E> q = p.next; |
| 64 | + if (q == null) { |
| 65 | + // p is last node |
| 66 | + if (p.casNext(null, newNode)) { |
| 67 | + // Successful CAS is the linearization point |
| 68 | + // for e to become an element of this queue, |
| 69 | + // and for newNode to become "live". |
| 70 | + if (p != t) // hop two nodes at a time |
| 71 | + casTail(t, newNode); // Failure is OK. |
| 72 | + return true; |
| 73 | + } |
| 74 | + // Lost CAS race to another thread; re-read next |
| 75 | + } |
| 76 | + else if (p == q) |
| 77 | + // We have fallen off list. If tail is unchanged, it |
| 78 | + // will also be off-list, in which case we need to |
| 79 | + // jump to head, from which all live nodes are always |
| 80 | + // reachable. Else the new tail is a better bet. |
| 81 | + p = (t != (t = tail)) ? t : head; |
| 82 | + else |
| 83 | + // Check for tail updates after two hops. |
| 84 | + p = (p != t && t != (t = tail)) ? t : q; |
| 85 | + } |
| 86 | + } |
| 87 | +``` |
0 commit comments