本文是参考了https://www.javadoop.com/post/AbstractQueuedSynchronizer 该篇博客,然后根据他写的思路将加锁的过程转化为流程图。

流程图不太标准。

加锁

未命名文件

解锁

释放的流程就不再画图,过程如下:

  1. 首先调用release(1)方法。

  2. 该方法内部,会先调用tryRelease(1)方法。

  3. tryRelease方法中,会先判断当前线程是否是持有锁的线程,如果不是就返回异常,如果是,则判断释放一次锁后锁的标志位是否为0,如果为0则意味着没有重入,直接全部释放,否则不能完全释放。

  4. 如果调用tryRelease(1)成功,则会回到release方法中。后续会先获取到头节点,并判断状态,如果都没事,就唤醒后继节点。

    1
    2
    3
    4
    5
    6
    if (tryRelease(arg)) {
    Node h = head;
    if (h != null && h.waitStatus != 0)
    unparkSuccessor(h);
    return true;
    }
  5. unparkSuccessor方法内部,会先判断头节点状态,如果不是0就改为0。之后获取后继节点,如果不为空,则唤醒,如果为空,则从队列的队尾从前遍历,将其中status小于0的设置为下一个待唤醒的线程。

细节

waitStatus 初始化为0,然后是后一个节点修改前一个节点的waitStatus 的值。一般都是改为-1。waitStatus 为-1表示的是后继节点需要唤醒。

即这个waitStatus 并不代表自身的状态,而是后继节点的状态。