ReentrantLock公平锁流程图及示例
2022-01-12 17:16:52 5 举报
ReentrantLock公平锁流程图及示例
作者其他创作
大纲/内容
是
waitStatus为-1?
waitStatus=0
cas取锁成功?
将node作为head节点并返回中断状态
否
tail
tail为null?
null
enq
head
示例
返回false
next
thread
获取锁成功后会执行setHead方法
调用线程的中断方法
再次判断tail是否为null?
cas成功?
2
lock开始
exclusiveOwnerThread
当前线程被中断或该锁被unpark?
1
线程中断状态为true?
5
4
unparkSuccessor方法中会重置head节点的waitStatus为0,并对head节点的next节点所引用的线程(即t2线程)执行unpark操作t2线程被重新唤醒,parkAndCheckInterrupt方法返回false。会再次进行5中的循序。这时5中通过tryAcquire就能获取到锁了(为方便查看,下面贴出了5中的部分代码)
释放锁时会先执行tryRelease设置state值,只有当state设置为0时才表示锁可以被释放了(存在锁重入的情况时state会大于1)当tryRelease返回true且head不为null且head的waitStatus!=0(在6中会将head节点waitStatus值设置为-1)则会执行下面的unparkSuccessor方法
实例化一个Node节点并通过cas操作将该节点作为head节点
该方法中会调用LockSupport.park将当前线程挂起,有两种情况会重新唤醒该线程1. 其他线程中断了该线程,这种请求该方法返回true,并会重置中断状态。一旦该方法返回true将会设置5中的interrupted值为true 那么后续当前线程获取到锁时5会返回true,则在2中会执行selfInterrupt方法进行中断该线程,这样做是让外面获取锁的代码知道线程被中断过(因为part方法挂起线程后被中断后不会抛出异常)2. 线程t1执行完成后释放锁,也可能会唤醒当前线程(之所以说是可能是因为非公平锁在1中获取锁的时候会先执行一次cas操作没取到锁才会进入队列等待 在t1释放锁的时候可能会被其他线程通过这次cas抢走锁),释放锁的代码如下
prev
通过当前线程实例化为一个node对象
t2
cas设置成功?
设置interrupted值为true
shouldParkAfterFailedAcquire
3
AbstractQueuedSynchronizerstate=1
enacquireQueued
第一次进入该方法后pred.waitStatus值为0,所以会执行else将pred节点的waitStatus值设置为-1并返回false由于该方法返回false。返回false后在5中会进行新一轮的循环,最终还会进入该方法,此时由于pred.waitStatus值为-1了所以该方法会返回true,此时会回到5中执行下面的parkAndCheckInterrupt方法
7
中断状态为true?
假设有t1和t2两个线程同时执行lock进行取锁操作,t1先执行cas操作取到了锁,则t2执行cas操作会失败,会进入下面的acquire方法
acquire
LockSupport.park挂起当前线程
返回并重置线程中断状态
lock结束
返回node
parkAndCheckInterrupt
addWaiter
第一次循环的时候由于tail为null,所以会先实例化一个Node对象作为队列的head,并将head赋值给tail第二次循序的时候tail已经有值了,会进入else,执行完else后队列就是下面这个样子,最终将当前线程t2的node对象返回
t1
取出node的上一个节点p
通过cas将tail设置为当前线程node对象
通过上面操作将当前线程t2的node对象入队后,将该node作为参数调用acquireQueued方法node.predecessor主要是取出当前节点的上一个节点
通过cas将tail设置为node
waitStatus>0?
从4中的结构图中可以看出当前node节点的上一个节点是head节点,p==head。但由于t1未释放锁,所以tryAcquire会返回false最终会继续执行下面的shouldParkAfterFailedAcquire方法
删除取消节点
6
取出p节点的waitStatus值
ReentrantLock非公平锁(NonfairSync)lock流程图
首先会通过当前线程创建一个node对象,由于一开始AQS中的tail为null,所以会先执行下面的enq方法进行初始化队列的操作
cas设置waitStatus为-1
最终5中return方法的时候队列结构如下,之前的那个head节点会被垃圾回收
返回true
t2进入acquire方法后会再次尝试通过cas操作进行获取锁,如果还是没有取到则会进行下面的入队操作
p==head且tryAcquire取锁成功?
0 条评论
下一页