AQS
2023-04-14 22:39:42 0 举报
ReentrantLock公平锁、非公平锁源码解析
作者其他创作
大纲/内容
可重入锁
tail
return true
next
thread=线程2 waitState=0
共享变量state为0
Node
prev
thread=线程3 waitState=0
1.初始化队列 链表头尾节点重合2.节点入队
LockSupport.park(this);阻塞当前线程可以通过LockSupport.unpark(Thread)或其他线程调用该线程的中断方法(interrupt)口进行唤醒
parkAndCheckInterrupt()
thread=线程2 waitState=-1
头结点的后继节点不为空
第一步
加锁失败
lock
前驱节点为头结点
否
头结点waitstatus小于0
判断当前线程是否为独占线程
head节点出队
thread=线程2 waitState=-1
线程1调用unlock后最终CLH队列
acquireQueued阻塞队列
为0 资源可用
加锁成功
是
head
cas更新waitstatus为0
thread=线程3 waitState=0
enq方法
lock/unlock逻辑和非公平锁大致相同,唯一不同点在于tryAcquire方法,当当前资源空闲(state=0的时候),多了一个hasQueuedPredecessors方法判断,大致意思为,如果存在其他等待线程,那么自己也会加入到等待队列尾部,做到真正的先来后到,有序加锁
当前线程为独占线程
第二步
设置共享变量值为当前state-arg
线程2被lock.uppark后的最终CLH队列
ReentrantLock中的非公平锁加锁解锁流程
thread=null waitState=-1
不为头结点
ReentrantLock中的公平锁加锁解锁流程
当前node的前驱节点waitState为0
thread=null waitState=0
addWaiter(Node.EXCLUSIVE) 入队
总结tryAcquire通过对state做cas操作尝试获取锁addWaiter当前线程对应的Node入队acquireQueued阻塞当前线程LockSupport.park
线程3入队后最终CLH队列
p
setExclusiveOwnerThread(Thread.currentThread());设置独占线程为当前线程
如果进的是是分支返回true,否分钟返回false
获取当前node的前驱节点(addWaiter中入队的Node节点)
tryAcquire(acquires)
thread=null waitState=-1
shouldParkAfterFailedAcquire
头结点不为空,且头结点的waitStatus不等于0
thread=null waitState=0
设置当前独占线程为Null
线程1
获取当前state
tryRelease(arg)
线程2入队后最终CLH队列
unlock
release
thread=线程2 waitState=0
release方法总结:先cas改变共享变量state,再唤醒CLH队列中头节点的后一个节点。并设置头结点的waitstatus为0
有尾节点 新node节点入队没有创建队列并入队
t
线程2
设置为-1
true
不为0资源不可用
state+acquires 当前操作不需要cas因为当前线程就是获取到锁的线程
unparkSuccessor
线程3
LockSupport.unpark(s.thread);唤醒后继节点
0 条评论
回复 删除
下一页