并发编程(2)——AQS

AQS是什么?

AQS就是一个抽象队列同步器,abstract queued sychronizer,本质就是一个抽象类。

AQS中有一个核心属性state,其次还有一个双向链表以及一个单项链表。

首先state是基于volatile修饰,再基于CAS修改,同时可以保证三大特性。(原子,可见,有序)

其次还提供了一个双向链表。有Node对象组成的双向链表。

最后在Condition内部类中,还提供了一个由Node对象组成的单向链表。

AQS是JUC下大量工具的基础类,很多工具都基于AQS实现的,比如lock锁,CountDownLatch,Semaphore,线程池等等都用到了AQS。

 AQS为什么从后往前遍历?

如果线程没有获取到资源,就需要将线程封装为Node对象,安排到AQS的双向链表中排队,并且可能会挂起线程

如果在唤醒线程时,head节点的next是第一个要被唤醒的,如果head的next节点取消了,AQS的逻辑是从tail节点往前遍历,找到离head最近的有效节点?

想解释清楚这个问题,需要先了解,一个Node对象,是如何添加到双向链表中的。

基于addWaiter方法中,是先将当前Node的prev指向tail的节点,再将tail指向我自己,再让prev节点指向我

如下图,如果只执行到了2步骤,此时,Node加入到了AQS队列中,但是从prev节点往后,会找不到当前节点。

AQS为什么使用双向链表? 

因为AQS中,存在取消节点的操作,节点被取消后,需要从AQS的双向链表中断开连接。

还需要保证双向链表的完整性,

  • 需要将prev节点的next指针,指向next节点。

  • 需要将next节点的prev指针,指向prev节点。

如果正常的双向链表,直接操作就可以了。

但是如果是单向链表,需要遍历整个单向链表才能完成的上述的操作。比较浪费资源。

AQS为什么有一个虚拟的head节点? 

有一个哨兵节,点更方便操作。

另一个是因为AQS内部,每个Node都会有一些状态,这个状态不单单针对自己,还针对后续节点

  • 1:当前节点取消了。

  • 0:默认状态,啥事没有。

  • -1:当前节点的后继节点,挂起了。

  • -2:代表当前节点在Condition队列中(await将线程挂起了)

  • -3:代表当前是共享锁,唤醒时,后续节点依然需要被唤醒。

Node节点的ws,表示很多信息,除了当前节点的状态,还会维护后继节点状态。

如果取消虚拟的head节点,一个节点无法同时保存当前阶段状态和后继节点状态。

同时,在释放锁资源时,就要基于head节点的状态是否是-1。来决定是否唤醒后继节点。

如果为-1,正常唤醒

如果不为-1,不需要唤醒吗,减少了一次可能发生的遍历操作,提升性能。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值