队列类关系总览
1. ArrayQueue
环形队列
public class ArrayQueue<T> extends AbstractList<T> {
private int capacity; // 对象数组长度
private T[] queue; // 对象数组
private int head; // 头指针
private int tail; // 尾指针
}
常用方法
代码很简单,不多赘述,一看就能明白。不支持迭代器,遍历元素需要自己手动从head
开始到tail
public void resize(int newcapacity) {
int size = size();
if (newcapacity < size)
throw new IndexOutOfBoundsException("Resizing would lose data");
newcapacity++;
if (newcapacity == this.capacity)
return;
T[] newqueue = newArray(newcapacity);
for (int i = 0; i < size; i++)
newqueue[i] = get(i);
this.capacity = newcapacity;
this.queue = newqueue;
this.head = 0;
this.tail = size;
}
private T[] newArray(int size) {
return (T[]) new Object[size];
}
public boolean add(T o) {
queue[tail] = o;
int newtail = (tail + 1) % capacity;
if (newtail == head)
throw new IndexOutOfBoundsException("Queue full");
tail = newtail;
return true; // we did add something
}
public T remove(int i) {
if (i != 0)
throw new IllegalArgumentException("Can only remove head of queue");
if (head == tail)
throw new IndexOutOfBoundsException("Queue empty");
T removed = queue[head];
queue[head] = null;
head = (head + 1) % capacity;
return removed;
}
public T get(int i) {
int size = size();
if (i < 0 || i >= size) {
final String msg = "Index " + i + ", queue size " + size;
throw new IndexOutOfBoundsException(msg);
}
int index = (head + i) % capacity;
return queue[index];
}
public int size() {
// Can't use % here because it's not mod: -3 % 2 is -1, not +1.
int diff = tail - head;
if (diff < 0)
diff += capacity;
return diff;
}
2. LinkedList
属性一览
transient int size = 0;
/**
* Pointer to first node.
*/
transient Node<E> first;
/**
* Pointer to last node.
*/
transient Node<E> last;
// 每个元素封装成一个内部类 节点类型,
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
常用方法
// 尾巴上添加元素
public boolean offer(E e) {
return add(e); // ----> 调用 linkLast(e);
}
public void add(int index, E element) {
// ...
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
// 返回第一个元素
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
// 返回并删除第一个元素
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
// 在头上往里加,跟offer正好相反
public void push(E e) {
addFirst(e);
}
迭代器
// 支持从指定位置开始进行迭代
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
public boolean hasNext() {
return nextIndex < size;
}
public E next() {
// .. 各种检查代码略
lastReturned = next; // lastReturned 就是当前要返回的节点
next = next.next;
nextIndex++;
return lastReturned.item;
}
// 除了可以往下迭代之外,还可以往前迭代
// hasPrevious()
// previous()
// previousIndex()
3. ArrayDeque
双端循环队列,代码很简单不多讲。
public boolean add(E e) {
addLast(e);
return true;
}
public boolean offer(E e) {
return offerLast(e);
}
public E poll() {
return pollFirst();
}
public E pollLast() {
final Object[] es;
final int t;
E e = elementAt(es = elements, t = dec(tail, es.length));
if (e != null)
es[tail = t] = null;
return e;
}
public E peek() {
return peekFirst();
}
public E peekLast() {
final Object[] es;
return elementAt(es = elements, dec(tail, es.length));
}
public void push(E e) {
addFirst(e);
}
public E pop() {
return removeFirst();
}
// 删除指定位置的元素
boolean delete(int i) {
final Object[] es = elements;
final int capacity = es.length;
final int h, t;
// 计算出这个删除的元素是属于前半截还是后半截
final int front = sub(i, h = head, capacity);
final int back = sub(t = tail, i, capacity) - 1;
// 举例来说:
// 如果删除第十个元素,现在总共有1000个元素,肯定把前9个往后挪代价更低
if (front < back) {
// move front elements forwards
if (h <= i) {
System.arraycopy(es, h, es, h + 1, front);
} else { // Wrap around
System.arraycopy(es, 0, es, 1, i);
es[0] = es[capacity - 1];
System.arraycopy(es, h, es, h + 1, front - (i + 1));
}
es[h] = null;
head = inc(h, capacity);
return false;
} else {
// move back elements backwards
tail = dec(t, capacity);
if (i <= tail) {
System.arraycopy(es, i + 1, es, i, back);
} else { // Wrap around
System.arraycopy(es, i + 1, es, i, capacity - (i + 1));
es[capacity - 1] = es[0];
System.arraycopy(es, 1, es, 0, t - 1);
}
es[tail] = null;
return true;
}
}
private void grow(int needed) {
// overflow-conscious code
final int oldCapacity = elements.length;
int newCapacity;
// 如果当前容量 < 64 , 每次扩容直接翻倍容量, 否则只扩容50%
int jump = (oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1);
if (jump < needed
|| (newCapacity = (oldCapacity + jump)) - MAX_ARRAY_SIZE > 0)
newCapacity = newCapacity(needed, jump);
// 把之前老数组中的值拷贝到新数组
final Object[] es = elements = Arrays.copyOf(elements, newCapacity);
// Exceptionally, here tail == head needs to be disambiguated
if (tail < head || (tail == head && es[head] != null)) {
// wrap around; slide first leg forward to end of array
int newSpace = newCapacity - oldCapacity;
System.arraycopy(es, head,
es, head + newSpace,
oldCapacity - head);
for (int i = head, to = (head += newSpace); i < to; i++)
es[i] = null;
}
}
4. ArrayBlockingQueue
特性
- 循环队列
ReentrantLock
用作同步锁
常用方法
put()
当放不进去的时候,阻塞当前线程,直到放进去才继续执行代码
public void put(E e) throws InterruptedException {
Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
// 可以被打断的锁,加入等待队列之后可以取消自己的等待状态
// 线程被打断需要更新自己在等待队列的前后关系
lock.lockInterruptibly();
try {
// 如果当前队列已经满了,put线程进入 notFull 这个 condition队列阻塞
while (count == items.length)
// 这里会释放锁,然后unpark等待队列中的一个线程
// 即使是condition.await, 也是没什么用的,也都是加到同一等待队列中
// 源码逻辑既是如此
// unpark的下一个线程有可能是消费者也有可能是生产者
notFull.await();
// 队列中放入元素之后,需要把其他消费者线程唤醒
enqueue(e);
} finally {
lock.unlock();
}
}
private void enqueue(E e) {
// assert lock.isHeldByCurrentThread();
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = e;
if (++putIndex == items.length) putIndex = 0;
count++;
// 队列中放入元素之后,需要把其他消费者线程唤醒
// 虽然是这个这个condition,但是也都是去同一个队列中叫醒线程
notEmpty.signal();
}
offer()
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
Objects.requireNonNull(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) {
if (nanos <= 0L)
return false;
// 过期就需要把自己取消掉,然后更新在等待队列中前后等待关系
nanos = notFull.awaitNanos(nanos);
}
// 队列中放入元素之后,需要把其他消费者线程唤醒
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
private void enqueue(E e) {
// assert lock.isHeldByCurrentThread();
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = e;
if (++putIndex == items.length) putIndex = 0;
count++;
// 队列中放入元素之后,需要把其他消费者线程唤醒
// signalAll使用nextWaiter指针叫醒全部等待对列中的线程
notEmpty.signal();
}
poll()
队列为空
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
private E dequeue() {
// assert lock.isHeldByCurrentThread();
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E e = (E) items[takeIndex];
items[takeIndex] = null;
// 还是循环队列啊
if (++takeIndex == items.length) takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
// 叫醒生产者线程
notFull.signal();
return e;
}
take()
poll
的阻塞版本
poll
不出来等着
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
5. LinkedBlockingQueue
特性
- 链表
ReentrantLock
用作同步锁
理解了ArrayBlockingQueue
+ AQS
之后,代码相差无几
6. LinkedBlockingDeque
特性
- 双端队列,链表
ReentrantLock
用作同步锁
理解了ArrayBlockingQueue
+ AQS
之后,代码相差无几
7. PriorityQueue
特性
- 优先级队列,使用小顶堆来排序
小根堆插入图解
priorityQueue.add(1);
priorityQueue.add(6);
priorityQueue.add(5);
priorityQueue.add(7);
priorityQueue.add(8);
priorityQueue.add(18);
priorityQueue.add(0);
while(!priorityQueue.isEmpty()){
System.out.println(priorityQueue.poll());
}
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
// 数组不够长的时候进行数组扩容
// 数组长度小于64,直接翻倍容量,
// 过大的时候只扩容50%
// 调用 System.arrayCopy 复制到新的数组中
grow(i + 1);
// 向上滑动找到合适的排放位置
siftUp(i, e);
size = i + 1;
return true;
}
小根堆弹出图解
每次弹出堆顶元素
public E poll() {
final Object[] es;
final E result;
if ((result = (E) ((es = queue)[0])) != null) {
modCount++;
final int n;
final E x = (E) es[(n = --size)];
es[n] = null;
if (n > 0) {
final Comparator<? super E> cmp;
if ((cmp = comparator) == null)
// 使用默认排序规则进行排序
// 向下比较是否需要交换顺序
siftDownComparable(0, x, es, n);
else
// 如果有比较器,就用自己定义好的比较器进行排序
siftDownUsingComparator(0, x, es, n, cmp);
}
}
return result;
}
8. DelayQueue
特性
- 队列中只能
put
实现了Delayed
接口的类型 - 底层就是优先级队列
PriorityQueue
- 堆顶的元素要等着过期才可以取出,否则去取元素的线程就要
park
- 如果是第一个线程取就要
park
,要把自己设置为leader
,根据第一个元素过期时间计算好park
时间 leader
醒过来取走然后还要叫醒其他等待队列的线程
加锁版的PriorityQueue
而且使用的了Condition
等待队列
支持迭代器
public boolean offer(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 小根堆排序
q.offer(e);
if (q.peek() == e) {
leader = null;
// condition 等待队列
available.signal();
}
return true;
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
// 看看队列中有没有元素
E first = q.peek();
//如果队列为空,则直接去等待队列等待
if (first == null)
available.await();
else {
// 看看第一个元素的过期时间
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0L)
// 如果刚刚过期,或者已经过了,直接返回
return q.poll();
// 否则就要等着过期才可以返回
// 看看当前有没有线程等待
// 如果有线程 leader 不为空
// 自己则进入等待队列等待
first = null; // don't retain ref while waiting
if (leader != null)
available.await();
else {
// 把自己设置成leader
// 自己等待过期的纳秒数,然后再来重新获取第一个元素
Thread thisThread = Thread.currentThread();
leader = thisThread;
try {
available.awaitNanos(delay);
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
// 满足条件,叫醒所有等待队列中的线程
if (leader == null && q.peek() != null)
available.signal();
lock.unlock();
}
}
9. PriorityBlockingQueue
特性
-
使用了
ReentrantLock
用作同步锁, -
依然使用小顶堆排序,
-
依然每次
poll
弹出堆顶元素
常用方法
take()
阻塞版本poll
,poll
不出去就await
,依靠offer
方法唤醒
poll()
除了加了个锁之外跟普通的PriorityQueue
没什么区别
10. ConcurrentLinkedQueue
特性
- 使用
CAS
+自旋,不再使用ReentrantLock
内部类
// 存储的值被封装为Node
static final class Node<E> {
volatile E item;
volatile Node<E> next;
}
// 用VarHandle来指向所有的变量
// 可以直接获取变量的地址,进行CAS操作
private static final VarHandle HEAD;
private static final VarHandle TAIL;
static final VarHandle ITEM;
static final VarHandle NEXT;
static {
try {
MethodHandles.Lookup l = MethodHandles.lookup();
HEAD = l.findVarHandle(ConcurrentLinkedQueue.class, "head",
Node.class);
TAIL = l.findVarHandle(ConcurrentLinkedQueue.class, "tail",
Node.class);
ITEM = l.findVarHandle(Node.class, "item", Object.class);
NEXT = l.findVarHandle(Node.class, "next", Node.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
常用方法
offer()
public boolean offer(E e) {
final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
for (Node<E> t = tail, p = t;;) {
// 有的时候tail指针竟然会指在倒数第二个位置
// 此时 q 就不为空
Node<E> q = p.next;
if (q == null) {
// p is last node
// CAS操作替换 tail的next指针
if (NEXT.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this queue,
// and for newNode to become "live".
if (p != t) // hop two nodes at a time; failure is OK
// 继续用CAS操作设置新的尾巴为新创建的节点
TAIL.weakCompareAndSet(this, t, newNode);
return true;
}
// Lost CAS race to another thread; re-read next
}
// 有的时候tail指针竟然会指在倒数第二个位置
// 但大部分时候都是跳入下一个else中,
// 什么逻辑会触发这个 else if 有待于继续试验
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
// 把tail指向当前q的位置
// Check for tail updates after two hops.
p = (p != t && t != (t = tail)) ? t : q;
}
}
peek()
Node<E> first() {
// continue回到这个地方 restartFromHead
restartFromHead: for (;;) {
for (Node<E> h = head, p = h, q;; p = q) {
boolean hasItem = (p.item != null);
if (hasItem || (q = p.next) == null) {
// 有可能其他线程已经进行过了 poll,更改了头结点,
updateHead(h, p);
return hasItem ? p : null;
}
else if (p == q)
// 看到了新的写法,倒时很有意思
// continue回到 restartFromHead
continue restartFromHead;
}
}
}
poll()
public E poll() {
restartFromHead: for (;;) {
for (Node<E> h = head, p = h, q;; p = q) {
final E item;
// CAS:使用 null替换当前头节点的值
if ((item = p.item) != null && p.casItem(item, null)) {
// Successful CAS is the linearization point
// for item to be removed from this queue.
if (p != h) // hop two nodes at a time
updateHead(h, ((q = p.next) != null) ? q : p);
// 替换成功则返回 已经操作成功的Item的值
return item;
}
else if ((q = p.next) == null) {
updateHead(h, p);
return null;
}
else if (p == q)
continue restartFromHead;
}
}
}
11. ConcurrentLinkedDeque
特性
-
双端队列,比
ConcurrentLinkedQueue
多了指向pre
的指针,和从tail
弹出、从head
添加元素的操作, -
从获取
tail
和head
节点,到改变节点的pre
、next
指针全是CAS
操作 -
不再使用
ReentrantLock
用作同步锁
12. SynchronousQueue
特性
容量为0,相当于两个线程手把手递东西给对方。
其实准确讲队列容量不是为0,只是这个队列不是存放对象用的。每个线程去队列中 put / get
的时候,都是把自己注册进这个队列(也就是说这个队列是存放线程用)
-
不管是取元素还是放元素都会入队;
-
去队列中
get
的线程,模式为REQUEST
,去put
的线程模式为DATA
。 -
每个线程调用
put / get
时,先看看队列头是什么请求,put
拿着data
如果看到队列中第一个是 其他线程的get
请求,则get线程直接退出阻塞,返回数据,如果队头的模式跟当前线程的模式一样,则自己注册进队列。公平模式的话,FIFO,自己进入队列尾(公平模式)或者栈顶(非公平模式)。非公平模式队列变成了一个栈,所以当前线程push
进栈。 -
反之亦然。
-
入队之后,先自旋一定次数后再调用
LockSupport.park()
或LockSupport.parkNanos
阻塞; -
匹配之后解除阻塞,
LockSupport.unpark()
,保证线程解除阻塞之后能正常运转 -
SynchronousQueue
没有使用synchronized、重入锁,基本是通过 自旋+CAS
实现;
非公平模式图解
也就是说SynchronousQueue
的每一次put
操作,必须等待其他线性的poll
操作。
每一个poll
操作也必须等待其他线程的put
操作。
内部类
static final class SNode {
volatile SNode next; // next node in stack
volatile SNode match; // the node matched to this
volatile Thread waiter; // to control park/unpark
Object item; // data; or null for REQUESTs
int mode;
}
take() + put()
public E take() throws InterruptedException {
// 当一个线程去队列中take东西的时候,
// 调用transfer方法,
E e = transferer.transfer(null, false, 0);
if (e != null)
return e;
Thread.interrupted();
throw new InterruptedException();
}
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// 当一个线程去队列中put东西的时候,
// 调用transfer方法,
if (transferer.transfer(e, false, 0) == null) {
Thread.interrupted();
throw new InterruptedException();
}
}
// 调用 put get 真正干活的方法
E transfer(E e, boolean timed, long nanos) {
SNode s = null; // constructed/reused as needed
// 如果取东西,则模式为 request 模式
int mode = (e == null) ? REQUEST : DATA;
for (;;) {
// 公平模式下 交换队列是一个真正的队列,FIFO,head是队头
// 非公平模式模式下,交换队列是一个栈,head是栈顶
SNode h = head;
// 如果交换队列为空,或者两个模式相等
if (h == null || h.mode == mode) { // empty or same-mode
if (timed && nanos <= 0L) { // can't wait
if (h != null && h.isCancelled())
casHead(h, h.next); // pop cancelled node
else
return null;
// snode方法为新请求或者数据创建节点,然后CAS替换为自己头结点
//(LIFO非公平队列,公平队列的逻辑也差不多)
} else if (casHead(h, s = snode(s, e, h, mode))) {
// 尝试获取匹配线程,如果长时间匹配不到 park线程
// 如果匹配线程竟然是自己,表示这个节点已经被取消了(里边的线程已经超时或者被打断),清除当前节点,
SNode m = awaitFulfill(s, timed, nanos);
if (m == s) { // wait was cancelled
clean(s);
return null;
}
// 取出之后更新头结点
if ((h = head) != null && h.next == s)
casHead(h, s.next); // help s's fulfiller
// 更新完成之后返回数据
return (E) ((mode == REQUEST) ? m.item : s.item);
}
}
// 如果两个模式不一样,就是说一个take 碰见了 一个 put
// put 的 那个线程 可以给 take 的这个线程数据了
else if (!isFulfilling(h.mode)) { // try to fulfill
if (h.isCancelled()) // already cancelled
casHead(h, h.next); // pop and retry
else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
for (;;) { // loop until matched or waiters disappear
SNode m = s.next; // m is s's match
if (m == null) { // all waiters are gone
casHead(s, null); // pop fulfill node
s = null; // use new node next time
break; // restart main loop
}
SNode mn = m.next;
// 线程已经找到CP,弹出两个节点
// 并在 tryMatch 中调用 LockSupport.unpark,保证弹出线程可以正常运行
if (m.tryMatch(s)) {
casHead(s, mn); // pop both s and m
return (E) ((mode == REQUEST) ? m.item : s.item);
} else // lost match
s.casNext(m, mn); // help unlink
}
}
} else { // help a fulfiller
SNode m = h.next; // m is h's match
if (m == null) // waiter is gone
casHead(h, null); // pop fulfilling node
else {
SNode mn = m.next;
if (m.tryMatch(h)) // help match
casHead(h, mn); // pop both h and m
else // lost match
h.casNext(m, mn); // help unlink
}
}
}
}
SNode awaitFulfill(SNode s, boolean timed, long nanos) {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
int spins = shouldSpin(s)
? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
: 0;
for (;;) {
// 如果线程被打断,用CAS操作替换掉s中的waiter线程为null
if (w.isInterrupted())
s.tryCancel();
// 看看当前node有没有匹配的线程
// 如果有了,则直接返回匹配的那个节点
SNode m = s.match;
if (m != null)
return m;
// 如果设置了过期时间,看看线程有没有过期,过期直接取消线程
if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
s.tryCancel();
continue;
}
}
// 如果暂时还不用park,还有剩余的自旋次数(最多64次)
if (spins > 0) {
Thread.onSpinWait();
spins = shouldSpin(s) ? (spins - 1) : 0;
}
// 如果自己这个节点的waiter为空,把自己设置进这个节点的waiter中,
// 等待匹配之后能知道叫醒哪个线程
else if (s.waiter == null)
s.waiter = w; // establish waiter so can park next iter
// 阻塞线程,停止自旋
else if (!timed)
LockSupport.park(this);
else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
LockSupport.parkNanos(this, nanos);
}
}
13. LinkedTransferQueue
特性
-
LinkedTransferQueue
可以看作SynchronousQueue
(公平模式)、ConcurrentLinkedQueue
二者的合体; -
不管是取元素还是放元素都会入队;
-
至于是否入队及阻塞有四种模式,
NOW,ASYNC,SYNC,TIMED
; -
入队之后,先自旋一定次数后再调用
LockSupport.park()
或LockSupport.parkNanos
阻塞; -
匹配之后解除阻塞,
LockSupport.unpark()
,保证线程解除阻塞之后能正常运转 -
SynchronousQueue
没有使用synchronized、重入锁,基本是通过 自旋+CAS
实现; -
put
线程不用阻塞直接返回继续执行,相当于异步交付任务 -
take
线程是同步方法,取不到会阻塞
常用方法
put(), ASYNC
public void put(E e) {
// 调用xfer方法,参数为 ASYNC
xfer(e, true, ASYNC, 0);
}
private E xfer(E e, boolean haveData, int how, long nanos) {
if (haveData && (e == null))
throw new NullPointerException();
restart: for (Node s = null, t = null, h = null;;) {
// put 模式,先把 p 直线队尾
for (Node p = (t != (t = tail) && t.isData == haveData) ? t
: (h = head);; ) {
final Node q; final Object item;
// 如果当前队尾的是调用take方法的线程插进来的
if (p.isData != haveData
&& haveData == ((item = p.item) == null)) {
if (h == null) h = head;
// 直接匹配队尾的元素给当前线程,
// 然后调用 LockSupport.unpark(),解除线程的阻塞
if (p.tryMatch(item, e)) {
if (h != p) skipDeadNodesNearHead(h, p);
return (E) item;
}
}
// 如果队尾的节点模式是一样的,就要用CAS操作把这个put元素加到队尾
if ((q = p.next) == null) {
if (how == NOW) return e;
if (s == null) s = new Node(e);
if (!p.casNext(null, s)) continue;
if (p != t) casTail(t, s);
// put模式都是 ASYNC,所以put线程不用阻塞直接返回继续执行。相当于异步交付任务
if (how == ASYNC) return e;
return awaitMatch(s, p, e, (how == TIMED), nanos);
}
if (p == (p = q)) continue restart;
}
}
}
take(), SYNC
- 跟put代码一样,只是这次入队的是
take
的线程,而且take
不到就要阻塞
private E xfer(E e, boolean haveData, int how, long nanos) {
if (haveData && (e == null))
throw new NullPointerException();
restart: for (Node s = null, t = null, h = null;;) {
// take 模式,先把 p 直线队尾
for (Node p = (t != (t = tail) && t.isData == haveData) ? t
: (h = head);; ) {
final Node q; final Object item;
// 如果当前队尾的是调用take方法的线程插进来的
if (p.isData != haveData
&& haveData == ((item = p.item) == null)) {
if (h == null) h = head;
// 直接匹配队尾的元素给当前线程,
// 然后调用 LockSupport.unpark(),解除线程的阻塞
if (p.tryMatch(item, e)) {
if (h != p) skipDeadNodesNearHead(h, p);
return (E) item;
}
}
// 如果队尾的节点模式是一样的,就要用CAS操作把这个put元素加到队尾
if ((q = p.next) == null) {
if (how == NOW) return e;
if (s == null) s = new Node(e);
if (!p.casNext(null, s)) continue;
if (p != t) casTail(t, s);
if (how == ASYNC) return e;
// 既然这次是take操作,操作码为 SYNC, 跳入此方法执行,awaitMatch 等待匹配
// 先自旋一段时间,然后调用LockSupport.park
return awaitMatch(s, p, e, (how == TIMED), nanos);
}
if (p == (p = q)) continue restart;
}
}
}
remove()
- 移除元素的时候,把等待队列中的元素删除的同时要保证线程不被继续阻塞(因为有可能此时等待队列中的为
take
线程),所以仍然需要调用tryMatch
方法中的LockSupport.unpark
- 此时的逻辑是传参数为
null
,tryMatch(item, null)
- 之前的逻辑是用新创建的匹配节点,如果匹配成功就把两个出队
public boolean remove(Object o) {
if (o == null) return false;
restartFromHead: for (;;) {
for (Node p = head, pred = null; p != null; ) {
Node q = p.next;
final Object item;
if ((item = p.item) != null) {
if (p.isData) {
// 移除元素的时候,把等待队列中的元素删除的同时要保证线程不被继续阻塞
// (因为有可能此时等待队列中的为`take`线程),
// 所以仍然需要调用 `tryMatch`方法中的`LockSupport.unpark`
if (o.equals(item) && p.tryMatch(item, null)) {
skipDeadNodes(pred, p, p, q);
return true;
}
pred = p; p = q; continue;
}
}
else if (!p.isData)
break;
for (Node c = p;; q = p.next) {
if (q == null || !q.isMatched()) {
pred = skipDeadNodes(pred, c, p, q); p = q; break;
}
if (p == (p = q)) continue restartFromHead;
}
}
return false;
}
}