一、ReentrantLock释放锁过程
ReentrantLock的unlock()方法不区分公平锁还是非公平锁。
-
首先调用unlock()方法。
-
unlock()底层使用的是Sync.release(1)方法
public void unlock() { sync.release(1); }
-
release(1)方法会调用tryRelease(1)去尝试解锁。
public final boolean release(int arg) { //尝试释放锁 if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) //如果释放锁成功,而且等待队列不为空,且有一个以上的等待线程 //因为只有下一个线程才能将前一个线程的waitStatus的状态改为-1,head表示当前执行的线程 //当head不为空,且waitStatus !=0说明有等待线程初始化了等待队列,且将持有锁线程的 //等待状态改为了-1,必然存在等待线程,将队头的第一个唤醒 unparkSuccessor(h); return true; } return false; }
-
tryRelease(arg)尝试释放锁
@ReservedStackAccess protected final boolean tryRelease(int releases) { //释放一次锁,就将重入的次数减掉1 int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; //如果锁得状态为1,则表示锁真正被释放了,将持有锁的线程置为null if (c == 0) { free = true; setExclusiveOwnerThread(null); } //否则,锁依然被持有,因为该锁被持锁线程重入了多次 setState(c); return free; }
-
如果tryRelease()释放锁成功,且判断等待队列确实有阻塞线程,则尝试唤醒
private void unparkSuccessor(Node node) { //如果等待的线程状态<0,SIGNAL,将其设为0 int ws = node.waitStatus; if (ws < 0) node.compareAndSetWaitStatus(ws, 0); Node s = node.next; //找一个符合条件,即真正在阻塞睡眠的线程 if (s == null || s.waitStatus > 0) { s = null; for (Node p = tail; p != node && p != null; p = p.prev) if (p.waitStatus <= 0) s = p; } //找到后,将其唤醒。有个疑问,头节点不变化嘛??? if (s != null) LockSupport.unpark(s.thread); }
回答自己的疑问,为啥没有操作头节点呢?这是因为唤醒阻塞的第一个线程后,它会重新去获取锁,而不是直接将锁分配给它。
final boolean acquireQueued(final Node node, int arg) { boolean interrupted = false; try { for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC return interrupted; } if (shouldParkAfterFailedAcquire(p, node)) //从此处被唤醒后,重新进行循环,尝试去争抢锁,如果没抢到,则继续阻塞(非公平的时候) //当刚被唤醒,循环一次,此时p==head,同时如果tryAcquire(1)去获得锁, //如果获得成功将自己设置为head, //如果获得锁失败,则自己再自旋一次(因为在释放锁的时候,head的ws又重置为0了). //如果还是失败,则自己再次park()睡眠 interrupted |= parkAndCheckInterrupt(); } } catch (Throwable t) { cancelAcquire(node); if (interrupted) selfInterrupt(); throw t; } }
二、流程图
借用一下大佬的(比我考虑的多太多了):
引用:
https://blog.csdn.net/nrsc272420199/article/details/105442016
版权声明:本文为sinat_38705282原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。