JUC 系列:AQS -->学习 Doug Lea 大神思想

Posted offerNotFound

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC 系列:AQS -->学习 Doug Lea 大神思想相关的知识,希望对你有一定的参考价值。

AQS:全称是AbstractQueuedSynchronizer,一个并发同步管理框架类,是 JUC 的灵魂抽象类。如果要自己去实现一个同步管理框架呢?

个人学习寒食君大佬的解析后觉得可以分为三点:

  1. 通用性,下层实现透明的同步机制,同时给上层提供业务代码编写的功能
  2. 利用 CAS 操作,原子的修改共享标志位(由这个标志位来判断共享资源是否空闲)
  3. 等待队列(埋伏笔:情况①:当共享资源被占用时,直接返回结果、情况②:当共享资源被占用时,让后续的线程进入到等待队列中等待)

与 AQS 的结构有着异曲同工之妙,下面就记录下 AQS 的要素吧(本文只写了独占式的过程,共享式也大差不差)。

AQS 的成员变量属性


这里的state(注意使用了 volatitle关键字修饰)为什么不是布尔类型而是整数类型呢?因为这就牵扯到了 AQS 的两种模式 --> 共享模式、独占模式

  • 独占模式:当共享资源被一个线程占用时,其他线程无法占用
  • 共享模式:当共享资源被一个线程占用时,其他共享模式下的线程能占用

state为了表示占有资源的线程数量,所以采用的是整数类型。

队列里的节点有两种模式,就是独有和共享:

再来看一下节点 Node 的成员变量:


waitStaus用来判断线程是否需要挂起(后文有写)。

AQS 的重点就是如何利用标志位state和这个 FIFO 等待队列来管理多线程的同步状态,AQS 也把这些操作封装成了一些方法tryAcquireacquire(对应着前文的伏笔,tryAcquire:尝试获取锁,直接返回结果,acquire:获取锁,进入等待队列,直至获取成功)。

AQS 的核心方法

tryAcquire

该方法被 protected 修改,传入的参数是一个整数,返回一个布尔类型,但方法中只抛出了一个异常。这样做的目的是:让继承的子类必须去重写这个方法,否则就抛出不支持该操作的异常,这种设计就是给了上层调用者开发的空间。


在上层调用了tryAcquire方法获取到锁后,就去做自己的业务,做完后释放资源;如果获取失败,开发者的这个功能必须要操作这个共享资源呢,那就去调用acquire方法进入到等待队列。

acquire


该方法由 public final修饰,表明所有的继承类都可以直接调用这个方法,而且不允许子类去把这个方法重写(很显然,这就是告诉你,调用这个方法是一定能得到锁的)

在 if 判断语句里,你tryAcquire获取锁失败再去判断&&之后的条件,如果是获取到了锁那就直接结束。接下来看第二个判断条件:acquireQueued(addWaiter()),方法嵌套。

addWaiter

这个方法的作用就是将当前线程封装成一个 node,然后加入等待队列中。源码步骤:

  1. 创建一个线程节点
  2. 将该节点放到队尾,如果当前尾节点为空或第一次尝试 CAS 操作失败,则进入完整的入队方法enq
  3. enq方法中采用 CAS + 自旋的操作保证插入成功

疑问:为什么不直接在addWaiter方法中完整入队呢?其实注释中就已经告诉了,先尝试快速入队,不行再完整的入队。

acquireQueued

该方法是对线程进行挂起和响应,以此来实现队列的先进先出。

这两个方法就是当线程使用完共享资源后释放锁的方法。

所以流程总结就是:

如果当前节点是头节点的下一个,那么将会自旋是不断尝试拿锁,直到拿锁成功;否则进行判断是否需要挂起(判断条件:该节点前除了head节点,还有其它节点的,并且waitStaus为 SIGANL,那么该节点就需要挂起),这样就能保证 head 之后只有一个节点在通过 CAS 来获取锁,就能最大限度的避免无用的自旋来消耗 CPU 资源。

在该节点使用完共享资源后(节点使用完锁后会采用setHead()方法,变成新的头节点,起一个占位作用),需要释放锁,将自己的waitStaus置为默认值0,然后程序将会从队列的尾节点向前进行搜索(为什么不从头向后找?因为在setHead()方法中,已经和队列切断联系了),找到 head 节点后的最近且waitStaus <= 0的一个节点并唤醒它去争抢这个锁(因为在前面它是被挂起了的)。这样回到了最开始的地方,形成了一个良好的闭环。

以上是关于JUC 系列:AQS -->学习 Doug Lea 大神思想的主要内容,如果未能解决你的问题,请参考以下文章

JUC 系列:AQS -->学习 Doug Lea 大神思想

JUC 系列:AQS -->学习 Doug Lea 大神思想

AQS系列- ReentrantLock的加锁

并发编程的基石——AQS类

doug lea malloc源码剖析之:sYSMALLOc

doug lea malloc源码剖析之:sYSMALLOc