ReentrantLock 源码层面解读
2020-07-13 15:11:37 0 举报
ReentrantLock 源码层面解读
作者其他创作
大纲/内容
ws < 0判断当前节点状态
AbstractOwnableSynchronizer.setExclusiveOwnerThread(Thread.currentThread)
pred.next = node;
true
cancelAcquire(node);
return
node.next = node;
NonfairSync.lock()
state==0
unparkSuccessor(node);
Node s = node.next;
compareAndSetHead(new Node()通过CAS创建头结点
ws > 0判断前任节点需要被取消
false
node.thread = null;Node pred = node.prev;
当前节点一定不是尾节点
CAS操作CAS成功,设置前任节点状态为SINGNAL,下次自旋到来时,就能够跳出自旋。另外就是多线程条件下,节点状态无法立即确定
node.prev = t;
这个时候的nodenode.thread=null;局部形成循环依赖,帮助GC
获取锁
AQS.selfInterrupt()
获取当前节点的前任节点进行同步队列中尝试获取锁的核心
return interrupted;
node
true前任节点的后继节点需要获取锁
返回当前节点当前节点添加同步队列成功
p == head判断前任节点是否是头结点
CAS成功与失败成功,说明同步队列续接成功失败,说明该该节点的后继节点被其他线程操作
经过遍历设置与判断之后,如果当前节点的后继节点不为空,那么一定是有效节点,那么直接唤醒
t == null判断尾节点是否为空
CAS成功尾节点被替换成功
s == null || s.waitStatus > 0
非公平锁ReentrantLock lock=New ReentrantLock()
唤醒当前节点的后继节点,那么设置当前节点的waitStatus==0,表示当前节点在同步队列当中,设置不需要锁
作用(最终目的):设置当前节点为尾节点进入队列,通过尾结点判断队列是否存在如果尾节点不存在,队列懒初始化创建头结点(CAS),并设置尾节点,继续判断循环;如果尾节点不为空,设置当前节点为尾节点(CAS);将node.prev进行覆盖为什么CAS存在失败的可能性???多线程情况下,存在其他线程同样在完成enq(node)操作,那么头结点被创建成功,尾节点也被创建成功;
false前任节点不是头结点
nextc < 0
int state=AQS.getState()
CAS操作如果前任节点还是尾节点,那么设置当前节点是尾节点;CAS成功,说明当前节点被设置为新的尾节点CAS失败,在多线程情况下,其他线程已经被设置成尾节点
多线程场景下,的确可能获取到Thread刚设置为null的节点
pred.thread != null判断前任节点线程是否不为空
设置当前接节点的Threa=null,表示一定不需要执行
next != null
从尾节点向前遍历节点,如果节点不为空,并且不是当前节点
t.next = node;
Node pred = tail;
int ws = pred.waitStatus;
如果前任节点无效,那么通过同步队列往前找有效的前任节点
CAS失败说明其他的节点也在被设置为尾节点那么当前节点就不是尾节点
boolean flag= AQS.hasQueuedPredecessors()
node.prev = pred = pred.prev;
s = t;
c==0
s != null
interrupted = true;
ws == Node.SIGNAL判断前任节点的后继节点是否需要获取锁
node.prev = pred
Node next = node.next;
false当前节点不是尾节点
ws = pred.waitStatus
return t;t并不是尾节点
判断遍历中的节点状态,判断是否需要获取节点
CAS成功,只有一个线程获取到锁,不用考虑多线程下的并发问题
throw new Error(\"Maximum lock count exceeded\");
pred != head判断前任节点是否头结点
false后继节点为null
中断当前线程
pred.waitStatus > 0判断前任节点是否取消
Node t = tail
设置前任节点的后继节点为当前节点
当前需要被取消的节点的后继节点为null,前任节点为头结点
是否公平
false尾节点不为空
Node predNext = pred.next;node.waitStatus = Node.CANCELLED;
AQS.acquire(int arg)
CAS操作懒初始化同步队列CAS失败,在多线程场景下,存在竞争,同步队列已经创建成功CAS成功,同步队列初始化成功,设置尾节点,这个时候即使存在多线程问题,那么只会在这个部分自旋,一直到尾节点不为null为止
异常标记如果在同步队列中尝试获取锁异常,那么取消获取
LockSupport.unpark(s.thread);
int nextc = c + acquires;
setExclusiveOwnerThread(current);
被其他线程唤醒,才能继续执行
setHead(node);p.next = null;failed = false;
当前节点是否需要park的状态无法确定,继续自旋尝试获取锁
return false;
enq(node)
return true;
t != null && t != node
AQS.setState(int nextC)
false前任节点是头结点
true当前节点是尾节点
t.waitStatus <= 0
说明同步队列存在
true获取锁成功
node == null
NonfairSync.tryAcquire(int arg)
boolean failed = true;
flag
获取前任节点的“等待状态”如果前任节点状态不为SIGNAL,那么就继续自旋为什么一定要是SINGNAL???如果前任节点不为SIGNAL,那么当前节点能够获取到锁是未知的,所以需要一直进行前任节点状态的判断与确定
true取消
true前任节点不是头结点
addWaiter(Node.EXCLUSIVE)其中Node.EXCLUSIVE==null
true/false
final Node p = node.predecessor();
tail = head;设置尾节点等于头结点
LockSupport.park(this);
lock.lock()
Thread.interrupted()
如果需要获取节点,那么设置当前节点的后继节点为遍历中的节点
false获取锁失败
要取消的节点的前任节点是头结点,直接唤醒前任节点的后继节点(直接唤醒当前节点的后继节点)
pred.waitStatus > 0
false如果为空
说明前任节点在尝试获取的时候异常了,也成了需要取消的节点
failed
节点状态:前任节点头结点前任节点需要被取消当前节点
当前节点为空,那么不需要做任何处理
setExclusiveOwnerThread(Thread.currentThread()
说明同步队列不存在
next.waitStatus <= 0
AQS.tryAcqurie(int arg)
setState(nextc);
CAS失败说明有其他线程在设置该前任节点的后继节点(也就是有新的节点在被添加到同步队列当中),对我们无影响,结束
是否成功
中断标记如果在同步队列中当前节点被中断,那么中断当前节点的对应线程
s = null;
current == getExclusiveOwnerThread()
final Thread current = Thread.currentThread();int c = getState();
FairSync.tryAcquire(int arg)
设置尾节点的前任节点为有效的遍历节点
return node;
当前需要被取消的节点的后继节点为正常需要获取锁的节点
FairSync.lock()
当前节点的后继节点无效那么从尾节点往前遍历,重新构建同步队列,一直到遍历中的节点等于当前节点为止
true不为空
当前节点无法获取锁,休眠等待前任节点唤醒,继续在同步队列中尝试获取锁
公平锁ReentrantLock lock=new ReentrantLock(true)
tryAcquire(arg)
从尾节点从后往前遍历,如果同步队列不为空,那么重新构建同步队列
当前需要被取消的节点的后继节点也需要取消
作用(最终目的):在同步队列自旋尝试获取锁判断同步队列中的当前节点能否获取锁如果无法获取锁,是否应该休眠或者抛出异常通过当前节点的前任节点判断当前节点的状态以及行为(队列中依赖前任节点)
取消当前节点,需要判断当前节点的特殊性1.存不存在2.当前节点前后的节点需要断开重连2.1获取有效的前任节点2.2当前节点是否尾节点2.3前任节点是否头结点
通过当前节点与当前节点的前任节点判断当前节点对应的线程是否应该休眠(只要不是头结点就判断应不应该休眠)
设置当前节点的前任节点为尾节点
作用(最终目的):确保当前节点添加到同步队列如果同步队列存在,那么直接返回当前节点,并添加到队列的尾部,充当尾节点(通过CAS完成);如果同步队列不存在,那么懒创建一个同步队列,并将当前添加到队列的尾部,充当尾节点(通过CAS完成)
int ws = node.waitStatus;
interrupted
true后继节点不为null
boolean interrupted = false;
当前任节点的waitStatus==SINGNAL,说明当前节点当下不可能获取到锁,需要休眠,被唤醒
true线程不为空
false不取消
pred != null判断尾节点是否为空
CAS操作CAS成功,说明获取锁成功CAS失败,说明获取锁失败
true前任节点是头结点
这个时候的node情况:1.node的后继节点为null2.node的后继节点也需要取消3.
ReentrantLock
t = t.prev
CAS操作设置当前节点取代前任尾节点CAS失败,在多线程场景下,存在竞争,尾节点可能已经被抢占,或者同步队列消费完,自旋,保证当前节点设置为尾节点成功为止CAS成功,那么当前节点被成功的设置为尾节点,设置前任节点的后继节点为当前节点,将同步队列连接起来,即使在多线程场景下,后面尝试获取锁的节点,只可能添加当前节点的后继节点上,所以这里设置前尾节点的后继节点为当前节点成功,不存在多线程异常
CAS成功当前节点的前置节点去除后继节点成功
true尾节点为空
这里节点的状态当前节点需要取消当前节点的Thread为null当前节点的status== Node.CANCELLED;当前节点不是尾节点当前节点的前任节点不是头节点当前节点的前任节点的Thread不为空当前节点的后继节点不为空当前节点的后继节点未被取消CAS操作设置前任节点的后继节点为当前节点的后继节点CAS成功,说明从同步队列取消当前节点成功,同步队列续接成功那么为什么会失败???CAS失败,说明前任节点的后继节点已经被设置成功
false线程为空
node == tail判断当前的要取消的节点是否是尾节点
Thread.current() == getExclusiveOwnerThread()
Sync.lock()
获取不需要取消的前任节点的后继节点设置当前节点的状态为取消
Node t = tail;
parkAndCheckInterrupt()
收藏
0 条评论
回复 删除
下一页