AQS 首节点为什么为null的虚节点
一句话总结
节点入队不是原子操作!!!
等待队列正在有线程进行初始化,但只是进行到了Tail指向Head,没有将Head指向Tail,此时队列中有元素,需要返回True。如果Head没有指向Tail,这种情况下也需要将相关线程加入队列中。所以这块代码是为了解决极端情况下的并发问题。
具体代码
一切要先从 tryAcquire
开始
1 | protected final boolean tryAcquire(int acquires) { |
在尝试获取锁的时候如果 State=0
(没有线程持有),会将锁的持有者设置为当前线程。
考虑到并发的问题,并没有因为状态为0就直接 setExclusiveOwnerThread(current)
,而是加了一个 hasQueuedPredecessors
的判断
s = h.next
1 | public final boolean hasQueuedPredecessors() { |
如上是查询是否有线程等待获取的时间超过当前线程。
如果说此时没有人获取锁,正常来说头和尾都是待初始化阶段都为null,那什么情况下才有可能 h != t
?
h != t
1 | private Node addWaiter(Node mode) { |
在添加新的节点时,如果 tail == null
会执行 enq
方法,通过死循环保证入列的成功。
tail == null
表示节点还没有初始化需要创建。
先通过 CAS
方式将 Head
设置为 new Node()
,设置成功再设置尾指针。
这个操作肯定不是原子性的,无法保证不被打断。所以 h != t
的情况就是发生在 compareAndSetHead(new Node())
和 tail = head
的间隙中。
- 本文标题:AQS 首节点为什么为null的虚节点
- 本文作者:SunRan
- 创建时间:2022-01-06 15:51:35
- 本文链接:https://lksun.cn/2022/01/06/AQS-首节点为什么为null的虚节点/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
评论