深入理解AQS - 简介

AQS(AbstractQueuedSynchronizer)是JUC(java.util.concurrent)locks包中的实现锁的基础。

它提供一个依赖于FIFO的等待队列,实现阻塞锁和相关同步器(信号量,事件等)的框架。依赖单个原子的int值,旨在成为大多数同步器的有用基础。

该类支持默认独占模式和共享模式之一或两者。在独占模式下获取时,其他线程尝试获取不能成功。多个线程获取的共享模式可能(但不一定)成功。

API中已经给出了详细的描述,AQS使用队列实现,并且使用int类型的值代表锁的状态。锁分为独占、共享两种类型。locks包下还有一个使用long来标识状态的实现,细节跟AQS一致。下面是它的实现类

AbstractQueuedSynchronizer类中需要子类实现的方法都已经列出:

  • tryAcquire,尝试获取独占锁
  • tryRelease,尝试释放独占锁
  • tryAcquireShared,尝试获取共享锁
  • tryReleaseShared,尝试释放共享锁
  • isHeldExclusively,当前线程是持有独占锁

ReentrantLockReentrantReadWriteLock中都分别实现了上面的方法。后面我会详细分别在其中的实现方式。

AQS使用队列实现,在代码中可以看到一个Node的静态内部类,它持有到前一个和后一个Node的引用。Node分为SHAREDEXCLUSIVE两种类型。包含一个waitStatus等待状态,通过CAS改变它的值。有以下几种状态:

  • 0 默认值,正常的同步节点。
  • CANCELLED = 1,Node由于超时或中断取消。节点永远不会离开这个状态。特别是,具有已取消节点的线程永远不会再次阻塞。
  • SIGNAL = -1,该节点的后续节点是阻塞的,所以当前节点在释放和取消时需要解除后继节点的阻塞。
  • CONDITION = -2,该节点当前在条件队列,在转换之前,status变成0,将不会使用同步队列节点。
  • PROPAGATE = -3,releaseShared应该传播到其他node,在doReleaseShared中设置(仅限头节点)以确保继续传播,即使其他操作已经介入。

在AQS中持有headtail Node节点,从而持有真个队列。

存在另一个内部类ConditionObject实现Condition接口,Condition实现类似于Object类的wait、notify方法,也是通过队列实现,在类内部持有firstWaiterlastWaiter Node节点。

LockSupport是锁实现中实现线程阻塞的基础。

以上是java.util.concurrent.locks包中核心类,后面我们会针对具体实现深入分析代码的实现。

坚持原创技术分享,更多深度分析、实践代码,您的支持将鼓励我继续创作!