深入理解 JUC:AQS 队列同步器( 七 )


资源的获取与释放前面的小节我们分析了 LockSupport 工具类 , 以及 AQS 同步队列和条件队列的设计与实现 , 这些都是支撑 AQS 运行的基础组件 , 本小节我们将正式开始分析 AQS 的实现机制 。
AQS 对应的 AbstractQueuedSynchronizer 实现类 , 在属性定义上主要包含 4 个字段(如下) , 其中 exclusiveOwnerThread 由父类 AbstractOwnableSynchronizer 继承而来 , 用于记录当前持有独占锁的线程对象 , 而 head 和 tail 字段分别指向同步队列的头结点和尾结点:
private transient Thread exclusiveOwnerThread;private transient volatile Node head;private transient volatile Node tail;private volatile int state;字段 state 用于描述同步状态 , 对于不同的实现类来说具备不同的用途:

  • 对于 ReentrantLock 而言 , 表示当前线程获取锁的重入次数 。
  • 对于 ReentrantReadWriteLock 而言 , 高 16 位表示获取读锁的重入次数 , 低 16 位表示获取写锁的重入次数 。
  • 对于 Semaphore 而言 , 表示当前可用的信号个数 。
  • 对于 CountDownLatch 而言 , 表示计数器当前的值 。
具体细节我们将在后面分析相应组件实现机制的文章中再展开说明 。
AbstractQueuedSynchronizer 是一个抽象类 , 在方法设计上引入了模板方法设计模式 , 下面的代码块中列出了所有需要子类依据自身运行机制针对性实现的模板方法:
protected boolean tryAcquire(int arg)protected boolean tryRelease(int arg)protected int tryAcquireShared(int arg)protected boolean tryReleaseShared(int arg)protected boolean isHeldExclusively()这里先简单说明一下各个方法的作用 , 具体实现留到后面分析各个基于 AQS 实现组件的文章中再进一步分析:
  • tryAcquire :尝试以独占模式获取资源 , 如果获取成功则返回 true , 否则返回 false 。
  • tryRelease :尝试以独占模式释放资源 , 如果释放成功则返回 true , 否则返回 false 。
  • tryAcquireShared :尝试以共享模式获取资源 , 如果返回正数则说明获取成功 , 且还有可用的剩余资源;如果返回 0 则说明获取成功 , 但是没有可用的剩余资源;如果返回负数则说明获取资源失败 。
  • tryReleaseShared :尝试以共享模式释放资源 , 如果释放成功则返回 true , 否则返回 false 。
  • isHeldExclusively :判断当前线程是否正在独占资源 , 如果是则返回 true , 否则返回 false 。
AbstractQueuedSynchronizer 中的方法实现按照功能划分可以分为两大类 , 即获取资源(acquire)和释放资源(release) , 同时区分独占模式和共享模式 。 下面的小节中主要对获取和释放资源的方法区分独占模式和共享模式进行分析 。
独占获取资源针对独占模式获取资源 , AbstractQueuedSynchronizer 定义了多个版本的 acquire 方法实现 , 包括:acquire、acquireInterruptibly , 以及 tryAcquireNanos , 其中 acquireInterruptibly 是 acquire 的中断版本 , 在等待获取资源期间支持响应中断请求 , tryAcquireNanos 除了支持响应中断以外 , 还引入了超时等待机制 。
下面主要分析一下 AbstractQueuedSynchronizer#acquire 的实现 , 理解了该方法的实现机制 , 也就自然而然理解了另外两个版本的实现机制 。 方法 AbstractQueuedSynchronizer#acquire 的实现如下:
public final void acquire(int arg) {if (!this.tryAcquire(arg) // 尝试获取资源// 如果获取资源失败 , 则将当前线程加入到同步队列的末端(独占模式) , 并基于自旋机制等待获取资源}}方法 AbstractQueuedSynchronizer#tryAcquire 的功能在前面已经简单介绍过了 , 用于尝试获取资源 , 如果获取资源失败则会将当前线程添加到同步队列中 , 基于自旋机制等待获取资源 。


推荐阅读