【Java】AQS底层实现

1、AQS内部实现
AQS是依赖内部的同步队列实现,也就是FIFO双向队列,如果当前线程竞争锁失败,那么AQS会把当前线程以及等待状态封装成一个Node节点加入到同步队列中,同时阻塞该线程,当同步状态释放时,会把首节点唤醒,使其再次尝试获取同步状态。

AQS队列内部维护的是一个双向链表,这种结构每个数据都有两个指针,分别指向直接的的前驱节点和后继节点,当线程抢占锁失败时候,会封装成Node加入到AQS中去。
在同步队列中,一个节点表示一个线程,他保存这线程的引用ThreadId,状态(watiStatus),前驱结点(pre),后继节点(next)。

2、节点状态waitStatus
每个节点包含了线程的的等待状态,是否被阻塞,是否等待唤醒,是否被取消。变量waitStatus则表示当前Node节点的等待状态,共有5中取值,cancelled,signal,condition,propagate,0
cancelled(1):表示当前节点已取消调度。当timeout或者中断情况下,会触发变更为此状态,进入该状态后的节点不再变化
signal(-1),表示当前节点释放锁的时候,需要唤醒下一个节点。或者说后继节点在等待当前节点唤醒,后继节点入队时候,会将前驱节点更新给signal
condition(-2),当其他线程调用了condition的signal方法后,condition状态的节点会从等待队列转移到同步队列中,等待获取同步锁。
propagate(-3),共享模式下,前驱节点不仅会唤醒其后继节点,同时也可能唤醒后继的后继节点。
0 ,新节点入队时候的默认状态。

3、添加节点addWaiter

先通过快速尝试设置尾节点,如果失败,则调用enq(Node node)方法设置尾节点,设置尾节点使用的CAS自旋。假如有两个线程t1,t2,同时进入enq方法 ,t==null表示队列是首次使用,需要先初始化,另一个线程cas失败,则进入下次循环,通过cas操作将node添加到队尾。

每个节点都必须设置前置节点的 ws 状态为 SIGNAL(-1),因为每个节点在休眠前,都需要将前置节点的 ws 设置成 SIGNAL。否则自己永远无法被唤醒,所以必须要一个前置节点,而这个前置节点,实际上就是当前持有锁的节点。
由于第一个节点他是没有前置节点的,就创建一个假的。
总结下来就是:每个节点都需要设置前置节点的 ws 状态(这个状态为是为了保证数据一致性),而第一个节点是没有前置节点的,所以需要创建一个虚拟节点。

private Node addWaiter(Node mode) {
        //根据给定的模式(独占或者共享)新建Node
        Node node = new Node(Thre
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值