就是返回了底层的state变量,也就是AQS的state
[](()hasQueuedPredecessors方法
这个方法是用来判断线程是否需要排队的(返回false不需要排队),因为是公平锁,所以这个判断是必须的,否则就不公平了,因为没有判断排队操作,那么只要一个线程释放了锁,那么后来的线程也是可以抢到的(透露一下:非公平锁的实现就是仅仅少了这个判断而已)
可以看到,这个方法是AQS里面的,tail和head属性前面已经提到过,是底层队列的头尾结点
关键在于return语句
他主要有两个判断
-
头结点是否等于尾结点
-
头结点是否尾空,或者头结点的线程是否为当前线程
关于这个弹出,必须要先清楚,底层队列里面的结点是怎么添加的
下面就是AQS的插入方法addWaiter
可以看到,如果尾结点不为空,也就代表不是第一次插入,那么直接就使用尾插法,如果是第一次插入,只是调用enq方法,所以enq方法是针对第一次插入使用的,这两个方法都是AQS的
可与看到里面是一个死循环,如果是第一次插入,让创建一个新结点为头结点(相当于一个哨兵),然后让新尾结点一样,这一点可以看成是初始化头尾结点,接下来下一轮循环,此时尾结点已经不为null,接下来就让新结点指向尾结点,让新结点又称为了尾结点,再让旧的尾结点指向新的尾结点
但这里有一个疑问,如果并不是第一次入队,为什么最后还要执行多一次enq方法呢?
我们可以看到,如果并不是第一次入队,因为前面的addWaiter,使用了一次CAS,那如果CAS失败了怎么办?即中途有线程把尾结点改了怎么办?
此时就需要重复的操作,不断的执行CAS直到成功为止,所以就有了无论哪次插入都要执行enq方法,因为enq方法里面就是一个死循环的CAS执行,直到CAS执行成功,才会结束
总结一下添加结点
-
所以头结点只是一个哨兵,是不存储线程的,而插入的方法则是尾插法
-
其实头结点也不完全是哨兵,下面我们看线程自旋时,会发现其实头结点是当前轮到执行的线程,这里先埋下个伏笔
知道了插入方法后,我们回过头来看hasQueuedPredecessors的返回值,也就是如何判断是否需要排队
步骤如下
-
判断头结点是否等于尾结点,只有在初始化的时候,头结点才会等于尾结点,或者队列为空,头尾结点都为null,所以,如果头结点等于尾结点(直接返回false),就代表了队列为空,所以就不需要进行排队