一图解释ReentranLock底层原理
2021-09-28 17:23:56 31 举报
一图解释ReentranLock底层原理
作者其他创作
大纲/内容
1.先尝试获取锁
否
继承
超类
acquire(1)
添加成功
state == 0没有被线程占用
Sync锁是否被线程占用?state = 0?
将当前队列添加到CLH队列尾
Lock
调用
注意:CLH队列会维护一个前驱节点,当前节点的pred == null 才是头节点,目的是方便判断,进行状态转换时也会简单许多
false
修改Sync对象State的值nextc = c + acquiressetState(nextc)
总结:如果锁没有被占用,非公平锁直接尝试获取锁,公平锁先判断是否有等待线程,没有再尝试获取锁。如果被线程占用则判断是否是当前线程占用,是就修改state状态,没有直接返回false执行后续代码
!非公平锁不判断直接尝试获取锁
ReentrantLock
当前节点是否为队列中的第一个节点?node.predecessor() == head ?
失败
是
Nonfair
true
free = true
模板方法模式
头节点不为空,且waitStaaatus不为0
FairSync
设置当前线程独占锁setExclusiveOwnerThread(Thread.currentThread())
设置当前占用访问权线程为nullsetExclusiveOwnerThread(null)
设置新的statesetState(c)
计算新的statec = getState() - releases如果不是当前线程占用锁抛异常
尝试获取锁成功返回TRUE
设置当前拥有独占访问权的线程
总结:入CLH队列后尝试获取锁,先判断是否为第一个节点,是的话尝试获取锁,未获取到锁或不是第一个节点且非阻塞会进行自旋,重复尝试获取锁,如果阻塞,返回当前中断状态
新的statec == 0 ?
3.在CLH队队列中尝试获取锁
初始化CLH队列compareAndSetHead(new Node())tail = head
Sync
getState()
release(1)
!tryAcquire(arg)
未获取到锁
添加失败自旋保证队列全部入队
尝试获取锁失败返回FALSE继续执行后续代码
同步队列中是否有等待线程 Node pred = tailpred != null ?
获取到锁
unLock()
tryRelease(arg) ?
实现
返回当前线程是否中断
是否是当前线程占用?current == getExclusiveOwnerThread()
LockSupport.unpark(s.thread)解除s.thread线程的阻塞
AbstractQueuedSynchronizer
selfInterrupt()->Thread.currentThread().interrupt()设置打断标记,将中断信号外传
逻辑
是这个类中的方法
return free
2.添加当前线程到CLH队列中EXCLSIVE独占模式
state != 0被线程占用
自我中断设置打断标记
setExclusiveOwnerThread()
将当前线程对应的Node对象从CLH队列移除,并重新设置队列
free = false
lock()
当前线程不再占用锁
成功
方法
判断CLH队列中是否等待的线程!hasQueuedPredecessors()
尝试获取锁tryAcquire()
Node h = headh != null && waitStatus != 0
总结:线程加锁失败后,将当前线程添加到CLH队列,如果队列中有等待线程,将当前队列添加到队列尾部,如果没有,先检查是否初始化,初始化了就添加到队列尾部,未初始化就先初始化一个队列再添加
AbstractOwnableSynchronizer
队列是否初始化tail == null ?
返回当前线程对应的Node对象
addWaiter(Node.EXCLUSIVE)
返回false
Fair无论成功失败
getExclusiveOwnerThread()
是队列中有等待线程
类/接口
否自旋重复执行for循环尝试获取锁
unparkSuccessor(h)唤醒节点的后继节点(如果存在)
阻塞当前线程,返回当前线程中断状态parkAndCheckInterrupt()
内部类
获取当前拥有独占访问权的线程
添加当前线程到队列中enq(Node)
NonfairSync
0 条评论
下一页