AQS 同步队列 简单分析

源码AbstractQueuedSynchronizer.java
同步队列 入口函数为 acquire 调用 独占锁:
如果tryAcquire失败.那么会一直等待直到成功.是一种阻塞锁.
在这里插入图片描述
因为acquire是一个阻塞锁.所以队列中有多个等待者,就有多少个线程.大体来说下过程
1.首先某个线程发起acquire获取锁的请求.如果成功很简单资源加锁就完了.主要是失败的处理.
2.如果请求锁失败,那么这时候会新生成一个Node对象包裹请求参数.加到队列尾部,值得注意的是这个队列是一个FIFO,有两个Node全局变量一个记录着head,一个记录着tail.
3.新加入的Node把prev指向tail,tail把next指向Node,最后把Node赋值给tail
4.每个等待的node对象.都在不停的判断它的前一个Node是不是head,如果是则它就不停的尝试获取锁(head拥有锁,只有等到它释放)
5.如图第二个节点,如果能成功的获取资源锁,则证明head已经释放了锁.那么这个时候第二个节点就把不客气的把自己弄成head.那么它的prev指向肯定就得为null.而之前的head这个时候已经没什么用了.把它的next指向质为null.这样互相引用就没了,应该更容易GC了.虽然GC能够处理这种相互引用,但是应该有代价吧.
6.重复上述过程. 下面对代码截图,对没说到的部分再说下在这里插入图片描述
起点函数就是acquire,通过它来获取锁.
tryAcquire是个空函数.需要继承者来重载,这里来看下acquireQueued实现在这里插入图片描述
第一个if基本就是上面说的那些.看第二个if高亮的函数定义在这里插入图片描述
这里上面就没说到.waitStatus是一个等待状态,这里new Node对象里并没有赋值,那么默认值就这0.看它的几种状态的定义在这里插入图片描述
看到基本都是小于0的,只有一个CANCEL = 1 .要注意的是,这个CANCEL是程序内部自己赋值的,也就是说当前线程被终止了.这个由cancelAcquire方法赋值.这个方法是个私有方法.而且从原理上不允许通过acquire后,再手动通过cancelAcquire取消调用.只能一直等待.否则的话这个node的for死循环线程一直存在,造成内存问题.

另外acquire在执行过程中是不能被中断的.有中断只会被置标记.执行完之后,会中断我们调用acquire那个线程.
所以一旦线程调用了acquire来请求锁,那么线程将一直阻塞直到获取锁.这期间没有任何办法来打断这个逻辑.所以如果我们想能够控制获取锁的时机,怎么办呢.那就是AQS的条件队列了.请看下篇的条件队列分析.

用acquireInterruptibly来中断,这个采用捕获InterruptedException这个异常,来达到中断的目地.

共享锁acquireShared .原理同上,只不过,独占锁,资源只有一个.而共享锁,有拥有多个资源.在资源没用完之前不会进行等待队列.资源用完时,一样处理.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bruk_spp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值