ReentrantLock源码
2022-11-11 17:14:08 1 举报
ReentrantLock源码
作者其他创作
大纲/内容
尝试获取锁
if (ws > 0)
直到空为止退出循环,遍历整个条件等待队列
enq(node);
if (first != null)
}
设置前一个节点的waitStatus为SIGNAL
Node next = t.nextWaiter;
final Node p = node.predecessor();
如果 lastWaiter 被取消,则清除。
返回
true
false
cas失败,尝试获取锁
ture
if (c == 0)
lock.unlock()
前一个节点是头节点并且获取到锁
enq(node)
node.prev = t;
唤醒一个线程
LockSupport.unpark(node.thread)
阻塞当前线程
condition.await()
if (h != null && h.waitStatus != 0)
没获取到锁并且加入了同步等待队列,并且中断标志位为true,重新设置中断标志位
t.next = node;
if (ws == Node.SIGNAL)
if (t != null && t.waitStatus != Node.CONDITION)
释放锁成功
exclusiveOwnerThread = thread;
cas获取锁成功
将当前节点设置为头节点,设置当前线程为null,节点的前指针为null,设置之前头节点的next为null,将之前头节点从队列中删除
unparkSuccessor(h)
LockSupport.unpark(s.thread)
reture false
尾节点不为空,已经构建了一个队列,进行入队逻辑
if (t.waitStatus <= 0)
firstWaiter指向下一个节点
addConditionWaiter()
release(savedState)
如果节点通过从尾部向前搜索在同步队列上,则返回 true。仅在 isOnSyncQueue 需要时调用。返回值:如果存在则为真
Node EXCLUSIVE = null
LockSupport.park(this);
trail.nextWaiter = next;
cas成功,返回当前线程节点
Node s = node.next;
头节点的下一个节点为null,被取消了
sync.lock();
获取锁,出队
condition.signal()
while (!isOnSyncQueue(node))
需要等待同步队列解锁逻辑,唤醒当前线程
再次进行循环
tryAcquire(arg)
tryRelease(arg)
Node t = lastWaiter;
判断头节点是否是条件状态
tryAcquir尝试获取锁
节点出队,如果是尾结点,cas设置前指针指向的节点为尾结点
cas设置头节点成功,将头节点赋值给尾节点,因为现在队列只有一个节点
tail = head;
while (!transferForSignal(first) && (first = firstWaiter) != null)
模式意味着退出等待时重新中断
false 是条件状态
将头节点的nextWaiter置空
Thread1
lock.lock()
reportInterruptAfterWait(interruptMode);
if (interruptMode != 0)
判断前一个节点的waitStatus
acquire(1)
从尾不开始查找一直到不为空,并且不是头节点为止,并且没被取消
cas设置当前CONDITION节点状态为0
trail = t;
enq(node)
入同步等待队列
以独占不间断模式获取已在队列中的线程。由条件等待方法和获取使用。参形:node ——节点 arg – 获取参数返回值:如果在等待时被打断,则为true
Node first = firstWaiter;
setHead(node);p.next = null; // help GCfailed = false;
Thread.interrupted()
if (next == null)
if (t.waitStatus != Node.CONDITION)
Node t = tail; for (;;) { if (t == node) return true; if (t == null) return false; t = t.prev; }
轨迹指向下一个节点
如果我们输给了一个signal(),那么我们不能继续,直到它完成它的enq()。期间取消不完全转移既罕见又短暂,所以就自旋吧。
fullyRelease(node)
if (node.nextWaiter != null)
cas失败,多线程环境尾节点已经改变,重新进入循环
lastWaiter = node;
返回0,没中断标志位,退出当前循环
nonfairTryAcquire(acquires)
释放锁,唤醒同步队列等待的线程
if (pred != null)
s = t;
唤醒同步队列的线程
Node t = tail;
if (compareAndSetHead(new Node()))
await必须处在独占获取锁状态调用
唤醒同步等待队列里的线程
node.waitStatus = Node.CANCELLED;
if (node.waitStatus == Node.CONDITION || node.prev == null)
setExclusiveOwnerThread(Thread.currentThread())
将当前节点前指针指向前一个节点的前一个节点,一直到waitStatus=0为止,将0的那些节点就从队列中删除了等待GC回收
判断是否中断,会清除中断标志位
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
for (;;) {
if (trail == null)
if (ws < 0)
if (s == null || s.waitStatus > 0)
while (!isOnSyncQueue(node))
!false
unlinkCancelledWaiters()
线程唤醒的逻辑就是unlock的逻辑,等待同步队列获取锁
cas失败,进入入队逻辑
lock.lock();
不在同步等待队列则自旋,转为就绪状态
do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);pred.next = node;
if (p == head && tryAcquire(arg))
设置独占线程
检查中断,如果在发出信号之前中断,则返回 THROW_IE,如果发出信号后返回 REINTERRUPT,如果没有中断,则返回 0。
条件等待队列转为同步等待队列
if (s != null)
if (failed)
lastWaiter不为空,且不为等待状态
没被中断
cas失败是多线程环境有别的线程已经创建了队列
THROW_IE
lastWaiter = trail;
isOnSyncQueue(node)
cas设置state
构建同步等待队列,并且入队
REINTERRUPT
cancelAcquire(node)
返回true,跳出循环
release(int arg)
Node t = firstWaiter; Node trail = null; while (t != null) {
findNodeFromTail(node)
当前线程存在于同步队列的头结点,调用await方法进行阻塞(从同步队列转化到条件队列)
if (failed)
for (Node t = tail; t != null && t != node; t = t.prev)
获取到锁
是当前获取锁线程state+1
t = next;
设置失败,条件队列的首节点放入同步队列
Thread0
返回false
if (t == null)
将要入队节点的前指针指向之前获取的tail,cas设置当前节点为尾节点,并把先前获取的tail的next指向当前节点,完成入队操作,及新进入同步队列的线程放入队尾
doSignal(first);
transferForSignal(first)
Thread.interrupted() ? (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0;
if (!isHeldExclusively())
Thread.yield();
判断是否时当前线程重入
cas设置当前线程节点为尾结点成功
else if (current == getExclusiveOwnerThread())
t.nextWaiter = null;
head = node;node.thread = null;node.prev = null;
节点状态置为取消
interruptMode = REINTERRUPT;
将当前线程置为等待状态,加入条件等待队列队尾,返回该节点
将条件队列的头节点加入到同步队列
LockSupport.park(this)
transferAfterCancelledWait(node)
if (node.next != null)
有中断标志位,取消后转移等待
cas失败
释放锁
在同步等待队列
selfInterrupt()
从条件队列中取消链接已取消的服务员节点。仅在持有锁时调用。这在条件等待期间发生取消时调用,并且在看到 lastWaiter 已被取消时插入新的等待者时调用。需要这种方法来避免在没有信号的情况下保留垃圾。因此,即使它可能需要完全遍历,它也只有在没有信号的情况下发生超时或取消时才会发挥作用。它遍历所有节点,而不是在特定目标处停止以取消链接到垃圾节点的所有指针,而无需在取消风暴期间进行多次重新遍历。
在这种情况下,waitStatus 可能是暂时且无害的错误
不在同步等待队列
获取当前线程获取state
判断同步等待队列头节点状态
Node h = head;
firstWaiter = next;
设置状态为0返回false,结束循环
cas设置头节点的waitStatus为0
parkAndCheckInterrupt()
获取锁失败阻塞
cas设置当前线程节点为尾节点
返回当前尾节点,及当前线程节点
获取当前线程节点的前一个节点
0 条评论
下一页