AQS

AQS核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,即将暂时获取不到锁的线程加入到队列中

两个队列

  • 条件队列是为Lock实现的一个基础同步器,并且一个线程可能会有多个条件队列,只有在使用了Condition才会存在条件队列。
  • 同步队列的作用是,在线程获取资源失败后,进入同步队列队尾保持自旋等待状态, 在同步队列中的线程在自旋时会判断其前节点是否为head节点,如果为head节点则不断尝试获取资源/锁,获取成功则退出同步队列。当线程执行完逻辑后,会释放资源/锁,释放后唤醒其后继节点。

https://tva1.sinaimg.cn/large/007S8ZIlly1gizdoe7qifj30je07y3yr.jpg

两种资源共享方式

  • Exclusive(独占):只有一个线程能执行,如ReentrantLock。又可分为公平锁和非公平锁:
    • 公平锁:按照线程在队列中的排队顺序,先到者先拿到锁
    • 非公平锁:当线程要获取锁时,无视队列顺序直接去抢锁,谁抢到就是谁的
  • Share(共享):多个线程可同时执行,如Semaphore/CountDownLatch。

模板方法

isHeldExclusively()//该线程是否正在独占资源。只有用到condition才需要去实现它。
tryAcquire(int)//独占方式。尝试获取资源,成功则返回true,失败则返回false。
tryRelease(int)//独占方式。尝试释放资源,成功则返回true,失败则返回false。
tryAcquireShared(int)//共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
tryReleaseShared(int)//共享方式。尝试释放资源,成功则返回true,失败则返回false。

独占获取同步状态

acquire

该方法将会调用子类复写的 tryAcquire 方法获取同步状态,

  1. 获取成功:直接返回
  2. 获取失败:将线程封装在节点中,并将节点置于同步队列尾部,自旋获取同步状态
    • 若获取成功,当前节点将自己设为头节点并返回
    • 如果在有限次内仍无法获取同步状态,该线程将会阻塞住,直到被前驱节点唤醒

共享获取同步状态

  1. 尝试获取共享同步状态,若获取失败,则生成节点,并入队
  2. 如果前驱为头结点,再次尝试获取共享同步状态
  3. 获取成功则将自己设为头结点,如果后继节点是共享类型的,则唤醒
  4. 若失败,将节点状态设为 SIGNAL,再次尝试。若再次失败,线程进入等待状态

ConditionObject

AQS中的ConditionObject内部类实现了Condition接口,配合锁对象使用实现等待、通知。

ConditionObject是通过基于单链表的条件队列来管理等待线程的。线程在调用await方法进行等待时,会释放同步状态。同时线程将会被封装到一个等待节点中,并将节点置入条件队列尾部进行等待。当有线程在获取独占锁的情况下调用signal或singalAll方法时,队列中的等待线程将会被唤醒,重新竞争锁。

https://tva1.sinaimg.cn/large/007S8ZIlly1gizdoisfwvj31820o40w6.jpg

await

await 是一个响应中断的等待方法,主要逻辑流程如下:

  1. 如果线程中断了,抛出 InterruptedException 异常
  2. 将线程封装到节点对象里,并将节点添加到条件队列尾部
  3. 保存并完全释放同步状态,保存下来的同步状态在重新竞争锁时会用到
  4. 线程进入等待状态,直到被通知或中断才会恢复运行
  5. 使用第3步保存的同步状态去竞争独占锁

signal

将条件队列中的头结点转移到同步队列中

signalAll

将条件队列中所有的节点转移到同步队列中