AQS源码研读

之前读的太粗糙,现在细读一下,结合容器一起看一下

首先要说明,AQS中队列使用双向链表实现,其中头节点为可能占有资源的线程(这里说可以是因为调用acquire的线程会在未入队前尝试竞争一次资源,如果成功则直接抢占,此时这个节点不需要入队,头节点也就不是占有资源的线程了)

AQS中一个节点代表一个线程,节点有一个状态,大于0为被取消状态,小于0为有效等待状态,0新节点默认状态

AQS的入口为acquire/release和acquireShared/releaseShared

首先在这里面调用用户实现的tryAcquire如果成功则直接返回(这里是非公平的,一个线程调用acquire时会试图抢占一下,尽管队列中还有别的等待线程),否则会阻塞在acquireQueued方法上,来看看具体怎么回事

可以看到addWaiter主要就是将新的节点插入队尾,这里使用了一个自旋,然后使用CAS实现的compareAndSetTail来插入队尾,如果插入失败则再次尝试将此节点加到新的队尾节点后面并更新队尾节点

acquireQueued则是试图竞争锁然后在竞争失败后阻塞。使用了一个自旋,在第一个if中判断是否是头节点的后一个节点,如果是则可以竞争锁了,如果tryAcquire成功则变为头节点,然后返回

如果不能竞争或竞争失败则到第二个if,shouldParkAfterFailedAcquire方法会维护一下队列,返回true则可以进入阻塞,返回false则需要再自旋来检查是否可竞争锁,来看看具体怎么回事

这里如果前一个节点设置为了SIGNAL则说明可以进入阻塞,直接返回true;否则,如果状态>0则CANCEL状态,则需要进入循环,将所有前面连续的CANCEL节点全移除出去,然后返回false,看移除后这个节点能不能竞争锁;或者前二者都不满足,则试图设置前一个节点为SIGNAL,然后返回false,查看是否能竞争锁

这里最后一种情况返回false查看是否能竞争锁的原因是,可能这个节点竞争锁的时候头节点还占有锁,但运行到此时头节点已经释放了锁,所以可以再尝试争取一下锁

接下来说release

 

 首先调用tryRelease,如果成功,则判断头节点是否为空或释放过的节点,如果不是则释放头节点,调用unpartSuccessor唤醒一个阻塞节点

这里可以看到,最后一个for循环会在下一个节点被cancel时找到最前面的未被cancel的节点,然后在最后用unpark唤醒。唤醒的节点则会在之前题到的acquireQueued方法中去请求锁。注意,这里没有清除唤醒节点前面的被cancel的节点,而是把这个工作放在acquireQueued中去做,在acquireQueued中会调用shouldParkAfterFailedAcquire用我们前面提到的方式清除cancel节点,然后在acquireQueued自旋中再试图请求锁

到这里就把acquire/release分析完了,share版本的操作基本一样,但是更复杂一点,因为如果头节点消费完资源后需要将剩余的资源向后传播,看能否满足后面的节点。关于acquire/release我们画个图

这里有两个问题,第一个问题,如果在release时代码抛出异常停止,而没有unpark后面的节点,就会陷入死锁。但release本身不会有异常,只有用户编写的tryRelease可能有不受检异常,所以一定注意tryRelease不要有bug

第二个问题,如果在shouldParkAfterFailedAcquire中A节点的ws为SIGNAL,然后此时这个线程被调度,另一个线程开始运行,执行了release操作成功释放资源,然后unpark下一个节点,恰好下一个就是A节点。那么,就会出现一个情况,A节点并没有运行到park,但是另一个节点却执行了它的unpark操作,会不会出现问题呢?

答案是不会,我去试了一下对一个线程先unpark再park这个线程不会阻塞,会继续运行。我记得有些锁就是这么设计的,当时看操作系统有说过

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值