ReentrantLock加锁流程
2021-02-17 10:29:58 0 举报
ReentrantLock公平锁加锁流程
作者其他创作
大纲/内容
2. CAStail
设置当前线程为独占线程
CLH队列
NO
addWaiter(Node.EXCLUSIVE)
return true
hasQueuedPredecessors()判断队列是否有前继节点Q2
节点进CLH队列队尾
通过CAS去修改state状态,获取锁资格
3. next
2. 创建一个空node,通过cas设置为队头,成功后赋值给队尾
该节点的前驱节点不是头节点或是头节点但没抢占到锁
判断前继节点的waitstatus
head
队尾是否为空
加锁成功
YES
return noInterrupted
如果为true,则park阻塞,如果不是,则会自旋,直到该线程要么争抢到锁,要么被park阻塞
return false
shouldParkAfterFailedAcquire方法是判断一个争用锁的线程是否应该被阻塞。它首先判断一个节点的前置节点的状态是否为Node.SIGNAL,如果是,是说明此节点已经将状态设置-如果锁释放,则应当通知它,所以它可以安全的阻塞了,返回true
因为进入到这步骤的只能是当前持有锁线程,所以不存在多线程之间的数据竞争
ReentrantLock公平锁加锁流程
return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());
AQS
分析:此方法本意是在CAS去争抢锁之前加一层判断,如果CLH队列中,有先抢占锁而阻塞的线程节点,则不参与此次争抢锁的行为,直接进入CLH队列。
3. 通过队头队尾初始化,在下一次自旋时,队尾不为空,执行节点添加进CLH队列队尾逻辑,具体逻辑见上图
add node
开始加锁
new tail
CAS
teturn ture
如果线程被中断,或者成功park则取消获取锁
enq(node)
lock()
new node
acquire(1)
1. 队列为空(head = tail = null)
为当前未抢占到锁的线程创建一个节点
park | 自旋
tail
node.prev = head
抢占锁是否成功
如果前继节点是“取消”状态,则设置 “当前节点”的 “当前前继节点” 为 “ '原前继节点' 的前继节点”。这个操作实际上是把队列中的CANCELLED节点剔除掉
设置当前当前节点为头节点,清除原头节点引用(同样,这个头节点的线程变量为null,这个节点代表持有锁线程)
获得该节点的前置节点node.prev
加锁线程是否为当前线程
old tail
CAS替换state为1
Q2:hasQueuedPredecessors()这个方法存在公平锁中,非公平锁中没有,能说下为什么吗?
Q1:为什么这里修改state状态不通过CAS修改?
FairSync extend Sync
waitStatus = Node.SIGNAL
这里说明之前通过CAS加锁失败
tryAcquire(1)
return fasle
waitStatus > 0
如果这个节点的前置节点是头节点,则再次执行抢占锁逻辑(头节点之前分析过了,是直接new node出的一个空节点,代表了当前持有锁的线程,所以以公平锁的视角来看,当持有锁的线程释放,该节点封装的线程就应该去抢占锁)
success
可重入加锁Q1
队头为空node
1. prev
return node
如果都不是,则设置该节点的前继节点的waitStatus为Node.SIGNAL
自旋,初始化队头后,节点进CLH队列队尾
ReentrantLock
state=0
收藏
收藏
0 条评论
下一页