AQS细致带你一步看清AQS源码及原理
2021-03-16 10:16:51 0 举报
最细致的剖析AQS原理,源码贴图+解析,每一步作用
作者其他创作
大纲/内容
尝试抢锁,该方法强制要求被实现,没有实现类则报错没有支持的错误,UnsupportedOperationException
承上启下,对之前锁定线程进行解锁(正常情况下为头结点(哨兵节点)下一个节点)
此时头结点(即哨兵节点)的下一个节点刚好是队列中第一个真实线程,可得该线程除非被拿掉或者有人修改了其状态(暂时没细究)否则不会进该方法
此处判断:可看到,如果当前线程又等于正在被占用的线程,则对当前线程多递增,继续占用
本次从非公平锁角度解析该方法
里面方法大致是从尾部节点开始往前找,只要大于零就将置为s(要释放锁的)节点,直到一个不为null或者是头节点(找到就覆盖,反正就是从尾巴往前找)
当前线程已经上位,顾将当前节点置为头结点(哨兵节点)
第一次进来应为默认state是0不会进入注意这里是自旋锁,所以第二次自选进来的时候就是Node.SIGNAL(-1),此时return true
setExclusiveOwnerThread
尝试解锁
开始解锁
release
true
parkAndCheckInterrupt
2
unparkSuccessor
注意这时waitStatus一定经过了自旋的第二步,此时应该是-1
AQS中state当前正在使用,所以getState值应该为1 此时传入结果1 ,计算结果c理当是0
此时将老的头结点的下一个节点置为null也即老的头结点没有任何引用,应该被回收了
1
结束
第一次进入尾部节点必然为空,创建一个新的空的节点,设置为列表中的头部节点,并将尾部节点也设置为这个空的节点
acquire
回到
总结:最后坐在候客区的前一节点一定是:Node.SIGNAL(-1)
继续release
false
此时返回的正常应该是未被中断的,直接返回interrupted=false
总结:AbstractQueuedSynchronizer内部节点中,首节点为标记节点,不处理业务逻辑,第一个进入链(队列中)必然有两个元素,首节点不为业务节点(线程),入队
从这开始阻塞线程,注意是阻塞,当前线程还在运行当中
此时线程中必然有线程嘛,所以走进unparkSuccessor方法
unlock
acquireQueued
tryRelease
addWaiter
相当于一个while循环
第一次进入state是0 进入的是该方法顾通过比较与交换,将ws,就是哨兵节点的值变成了Node.SIGNAL(-1)
lock
此时解锁
继续自旋锁
第二次进入不难发现,和之前addWaiter方法大同小异,将当前节点置于尾结点
作为方法的主入口
如果尾部节点不为空,则说明队列中有元素,将当前要添加的节点的前一个节点设置为的曾经尾节点,并将当前节点设置为尾部节点,最后将曾经的尾部节点的下一个节点设置为当前跟新的尾部节点
如果c是0,符合要求,当前线程也要解锁,释放阻塞,将占用的线程置为空,放出位置来供他人使用(类似与刚有一个去网点办理业务的人办完了,位置空出来了)
只有当前列表中的节点全部为空才会进入以下方法,如果尾部节点为空则创建头结点和尾部节点
最后线程未终端,interrupted=falseAQS结束
compareAndSetState
进来的如果是第二个节点,则上一个节点是哨兵节点(那个空节点),则会继续抢锁
3
当返回true时进入以下方法
此时将传入节点,也就是继续将头结点的state状态置为0
flase
enq
与lock的tryAcquire方法一样,该方法必须被实现,否则抛出不被支持
将当前线程作为使用线程,当前线程未执行完毕则其他线程阻塞
这个很简单,当前线程不是正在占用的线程抛出异常,具体为啥会这样判断,在研究一下
setHead
底层调用unsafe方法,底层cas比较并交换,如果如果成功,调用setExclusiveOwnerThread,将当前线程设置为占用线程
tryAcquire
自旋锁,返回值应该是false,此时回到自旋,应为之前有人unlock,ExclusiveOwnerThread中没有线程占用,state为0,此时tryAcquire可执行成功,再度进入if判断,此时p就是头结点,同时当前node节点可以抢占成功,此时当前node节点上位,进入if语句
0 条评论
回复 删除
下一页