AQS源码
2021-04-16 20:58:15 19 举报
AQS源码
作者其他创作
大纲/内容
true,执行上图步骤1
返回node
返回false
返回false,表示线程没有获取到锁
CAS获取锁
返回true,表示获取到了锁,线程逐级返回,加锁过程结束
addWaiter
final void lock() { acquire(1); }
lock
prev
abstract void lock()
sync继承了AbstractQueuedSynchronized
执行park逻辑
enq方法
acquire(1)
next
设置pred.waitState = -1
true
acquireQueued返回,表示线程获取到锁,线程逐级返回,加锁过程结束
执行排队逻辑
这个方法,接受两个Node对象参数:参数2是准备执行park操作的节点node,参数1是其前辈节点pred
Thread = ThreadBwaitState = 0
将当前对象封装为Node对象,并加到排队队列中根据排队队列是否执行过初始化,执行1,2不同处理逻辑1:表示排队队列不为空,也就是之前进行过初始化,此时只需将新的node加入到排队队列末尾即可2:表示排队队列为空,作为排队队列的head,然后将需要排队的线程,作为head的next节点插入
FairSync#lock()
返回true
public void lock() { sync.lock(); }
Ⅰ
公平锁
ReentrantLock
这个队列表示,在节点B插入队列之前,没有其他节点排队。注意,当前持有锁的线程,永远不会处于队列排队之中。这是因为,当一个线程调用lock获取锁时候,只有两种情况1)锁处于自由状态(state == 0),且他不需要排队,通过cas立即获取到了锁,这种情况,显然不会处于排队队列之中2)所处于非自由状态,线程加入到了排队队列的队头(不包括head)等待锁。将来某一时候,锁被其他线程释放,并唤醒这个排队的线程,线程唤醒以后,执行tryAcquire,获取到了锁,然后重新维护排队队列,将自己从对了移除(acquireQueued)方法。所以,不管哪种情况持有锁的线程,永远不会处于排队队列
NonFairSync#lock()
成功获取到锁,设置锁持有线程为当前线程,返回
非公平锁
false
没有其他线程在排队,调用enq构造队列,并将nodee加入到队列
Thread = nullwaitState = 0哨兵节点
尝试获取锁,如果获取不到,排队(阻塞当前线程)
整个aqs的核心难点之一:这里使用了for(;;)首先判断node的前辈节点,是不是head,如果是,说明他是下一个可以获得锁的线程,则调用一次tryAcquire,尝试获取锁,若未取到,则将链表关系重新维护下(node设置为head,之前的head从链表移除),然后返回如果node的前辈节点不是head,或获取锁失败,再判断前辈节点的waitState,是不是SINGAL(-1),如果是,则当前线程调用park,进入阻塞状态。如不是:1、 ==0 设置为SIGNALfont color=\"#000000\
pred != null
注意,这里是设置pred节点,而不是node节点的waitState。-1表示节点处于阻塞状态为何每个线程进入该方法后,修改的是上一个节点的waitState,而不是修改自己的?因为线程调用park后,无法设置自己的这个状态,若在调用park之前设置,存在不一致的问题。所以,,每个node的waitState,在后继节点加入时设置
pred.waitState>0?
false,执行上图步骤2
>0,只能==1.也就是CANCELLED。表示node的前辈几点。已经取消了,此时将链表关系重新维护下:也就是将其前辈节点从队列中移出
Ⅱ
HeadTail
Thread = ThreadCwaitState = 0
sync.lock()
false (即 ==0)
aqs队列
pred.waitState == Node.SIGNAL(-1)?
tryAcquire
队列已经初始化,将node加入到队列末尾,加入后队列可能如下
acquireQueued方法详解
acquireQueued
0 条评论
回复 删除
下一页