AQS源码
2021-04-22 16:40:42 20 举报
AQS源码解析
作者其他创作
大纲/内容
FairSync#lock()
ReentrantLock
acquireQueued
这部分,是 node 加入队列后的处理逻辑,这里会有一次自旋,尝试获取锁,获取不到,才调用 park,阻塞自己。
shouldParkAfterFailedAcquire 方法详解
acquireQueued 返回,表示线程获取到锁,线程逐级返回,加锁过程结束。
pred.waitState >0?
sync.lock()
表示获取到锁:1.node设置为头结点2.释放之前的头结点,这个逻辑执行完之后,node节点就不用进行排队了,(获取到锁的线程就不会再队列中)
返回 true,表示获取到了锁,线程逐级返回。加锁过程结束
队列尚未初始化,调用 enq 方法该方法生成一个空的 Node 对象(new Node(),右图粉色部分),插入到 aqs 队列头部,然后将参数 node ,作为后继节点,插入队列,方法执行完毕,队列如右图。
abstract void lock()
NonFairSync#lock()
这个队列表示,在线程 C 进入之前,已经有一个线程在排队获取锁了。
返回false
阻塞结束
lock
这个队列表示,在节点 n2 插入队列之前,没有其他节点在排队。注意,当前持有锁的线程,永远不会处于排队队列中。这是因为:当一个线程调用 lock 获取锁时,只有两种情况:1) 锁处于自由状态 (state==0) ,且它不需要排队,通过 cas 立刻获取到了锁,这种情况,显然它不会处于排队队列中;2)锁处于非自由状态,线程加入到了排队队列的队头 (不包括 head ) 等待锁。将来某一时刻,锁被其他线程释放,并唤醒这个排队的线程,线程唤醒后。执行 tryAcquire. 获取到了锁,然后重新维护排队队列,将自己从队列移出 (acquireQueued 方法)。所以,不管哪种情况,持有锁的线程,永远不会处于排队列表中。
没有其他线程在排队,调用 enq 构造队列,并将 node 加入队列。
false再次刷新
false,执行上图步骤2
acquireQueue 方法详解
设置 pred.waitState = -1
返回true
sync 继承了 AbstractQueuedSynchronizer
addWaiter
> 0 ,只能 == 1,即 CANCELLED。表示 node 的前辈节点,已经取消了,此时将链表关系重新维护下:即将其前辈节点从队列移出
这个方法,接收两个Node 对象参数:参数2 是准备执行 park 操作的节点 node,参数1是其前辈节点 pred.
pred ! = null
false,即==0
非公平锁
pred.waitState == Node.SIGNAL(-1)?
队列已经初始化,将 node 加入到队列末尾,加入后队列可能如下
false
尝试获取锁,如果获取不到,排队(阻塞当前线程)
true
tryAcquire
成功获取到锁,设置锁持有线程为当前线程。返回
acquire(1)
整个 aqs 的核心和难点之一。span style=\"font-size: inherit;\
执行pack逻辑
p == head ?表示查询 node 是不是第一个排队的
CAS获取锁
返回 false,表示线程没有获取到锁
公平锁
parkAndCheckInterrut 线程进入阻塞状态
返回node
0 条评论
回复 删除
下一页