一、AQS实现加锁image.png

公平锁:hasQueuedPredecessors方法,判断是否有前驱节点
尝试修改同步状态:

  • 如果当前同步器里的同步状态标识为0
    • 尝试使用CAS修改同步器状态
      • 修改成功:获取锁成功,将当前同步器的exclusiveOwnerThread(独占锁线程持有者)设置为当前线程
      • 修改失败
  • 当前同步器里的同步状态不为0
    • 判断当前线程是否是当前同步器的exclusiveOwnerThread(独占锁线程持有者)
      • 是,同步状态加1(锁可重入)

image.png
tryAcquire尝试修改同步状态失败情况下:
将当前线程加入队列addWaiter()

  • 尝试使用CAS+自旋的方式将当前节点设为尾节点
    • CAS入队列

image.png

  • 自旋CAS入队列

image.png


  • 线程入队后,不会马上被阻塞,在阻塞前会再判断一次,是否获取得到锁

    1. 因为将线程阻塞再唤醒太耗费CPU资源了,且考虑到可能上一个线程可能执行完了同步代码块
    2. 只有头节点的后面那个节点入队时才会再次尝试去获取锁
  • 将当前节点的前驱节点的waitStatus设置为-1

    释放锁后,在唤醒锁的时候需要先判断waitStatus的值

image.png

二、AQS实现解锁

image.png

  • 判断同步器中当前占有锁的线程是否是当前线程
    • 是,修改同步器状态为0

image.png

  • 释放锁成功后,获取head 节点的 next一个节点,使用LockSupport.unpark() 唤醒该节点线程
    • head的waitState 必须要 != 0(可唤醒状态)