1、源码装修

1.1 hasQueuedPredecessors()解析

https://blog.csdn.net/weixin_38106322/article/details/107154961

  1. public final boolean hasQueuedPredecessors() {
  2. // The correctness of this depends on head being initialized
  3. // before tail and on head.next being accurate if the current
  4. // thread is first in queue.
  5. Node t = tail; // Read fields in reverse initialization order
  6. Node h = head;
  7. Node s;
  8. return h != t &&
  9. ((s = h.next) == null || s.thread != Thread.currentThread());
  10. }

第一个判断等于这个方法:
head == tail要么是一起为null, 要么一起为虚拟头节点
head != tail表示队列中至少有两个不同节点存在,还有一种情况下面🌈处说明!

  1. /**
  2. *查询是否有线程在等待获取。 请注意,由于中断和超时导致的取消随时可能发生,
  3. *true返回并不能保证任何其他线程将永远获得。
  4. *在此实现中,此操作以恒定时间返回。
  5. * 返回:如果可能有其他线程等待获取,则为true
  6. **/
  7. public final boolean hasQueuedThreads() {
  8. return head != tail;
  9. }

所以会有很多种情况

hasQueuedPredecessors — true

  • 两边都为true

head != tail 表示队列中至少有两个不同节点存在。
(s = h.next) == null || s.thread != Thread.currentThread() — 任意一边为true

  • 🌈head != tail && (s = h.next) == null 这种特殊情况是处于下面图的这个位置:

image.png
那说明已经有节点尝试插入队列,根据FIFO的原理,我们这里应该是要排队

  • (s = h.next) == null 为fasle — 》s.thread != Thread.currentThread() 为true

就是后继节点不是当前线程,所以也需要排队.

hasQueuedPredecessors — false

  • h != t 为 false

即要么队列为空,头尾节点都会null;要么当h和t都指向同一个Node,也返回false。此时说明队列中只有一个dummy node,那说明没有线程在队列中。— 其实这里我认为有问题 ps:这种情况其实就是下面这两步执行好,可能原本的线程还在enq方法中自旋插入到同步等待队列,跟上面🌈处一样的道理,这里应该也需要排队.

  1. if (compareAndSetHead(new Node()))
  2. tail = head;
  • h != t 为 true, (s = h.next) == null || s.thread != Thread.currentThread()为false

    取非转换: (s = h.next) != null && s.thread == Thread.currentThread()

表示是当前节点排在后面,所以不用排队.