面试必考AQS-AQS概览

AQS介绍

AQS的含义

AQS是java.util.concurrent.locks.AbstractQueuedSynchronizer的简称,直译就是“抽象队列同步器”,它是java中大部分lock类的间接实现者。AQS中实现的各种逻辑非常精妙,在此膜拜一下Doug Lea老爷子。

刚刚有提到AQS间接实现了lock类,检查java中提供的lock类,如ReentrantLock,ReentrantReadWriteLock,StampedLock,CountDownLatch,CyclicBarrier等,内部都有AQS的实现类,完成了不同逻辑来承载不同Lock的实现。

 

AQS的构成

查看源码可知,大致有如下内容:

  • static final class Node {...} // 链表节点
  • public class ConditionObject implements Condition, java.io.Serializable {...} // 条件对象
  • private transient volatile Node head; // 链表头
  • private transient volatile Node tail; // 链表尾
  • private volatile int state; // 资源
  • private static final Unsafe unsafe = Unsafe.getUnsafe();// 用于cas操作的变量
  • private static final long stateOffset,headOffset,tailOffset,waitStatusOffset,nextOffset; // 用于cas操作的变量
  • 一些实例方法操作链表及资源
  • 一些抽象方法等待被实现

 

AQS的由来

在AQS的源码中,存在一个由head和tail构成的链表,在知晓它存在的作用前,先了解一下硬件领域的多核CPU架构。

从系统架构来看,目前的商用服务器大体可以分为三类,即对称多处理器结构 (SMP : Symmetric Multi-Processor) ,非一致存储访问结构 (NUMA : Non-Uniform Memory Access) ,以及海量并行处理结构 (MPP : Massive Parallel Processing) 。

 

处理器架构

SMP架构

即对称多处理器结构,在这种架构中,一台计算机由多个CPU组成,并共享内存和其他资源,所有的CPU都可以平等的访问内存、I/O等。虽然可以同时使用多个CPU,但从外部表现来看,它们就如同一台单CPU机器一样,操作系统将任务队列对称地分布于多个CPU之上,从而极大地提高了整个系统的数据处理能力。

日常的pc机,笔记本,手机还有一些老的服务器都是这个架构,其架构简单,但是拓展性能非常差,从linux 上也能看到:

ls /sys/devices/system/node/# 如果只看到一个node0 那就是smp架构
面试必考AQS-AQS概览_第1张图片  SMP架构图示

但是随着CPU数量的增加,每个CPU都要访问共享资源,而资源在某些场景下只能单线程访问,在某些场景下的操作又必须通知到其他CPU,那么这就带来了性能损耗、资源浪费,成为了系统瓶颈。

 

NUMA架构

即非一致存储访问,这种模型的是为了解决smp扩容性很差而提出的技术方案。它按组将CPU分为多模块,每个CPU模块由多个CPU组成,并且具有独立的本地内存、I/O等,模块之间的访问通过互联模块完成(类似远程通信),访问本地资源的速度会远高于访问外部资源。

面试必考AQS-AQS概览_第2张图片 NUMA架构图示

 

NUMA架构相当于打包多个SMP架构的CPU,它能较好解决SMP架构存在的扩展问题;但是,在NUMA的单个CPU模块中,虽然控制了CPU数量减少了共享资源的操作时的性能损耗,由于存在互联模块的工作,在CPU模块增加时,并不能线性的增加系统性能。

 

MPP架构

MPP 提供了另外一种进行系统扩展的方式,它由多个 SMP 服务器通过一定的节点互联网络进行连接,协同工作,完成相同的任务,从用户的角度来看是一个服务器系统。 其基本特征是由多个 SMP 服务器(每个 SMP 服务器称节点)通过节点互联网络连接而成,每个节点只访问自己的本地资源(内存、存储等),是一种完全无共享(Share Nothing)结构,因而扩展能力最好,理论上其扩展无限制,目前的技术可实现512个节点互联,数千个 CPU。 实验证明, SMP 服务器 CPU 利用率最好的情况是 2 至 4 个 CPU [1]。

面试必考AQS-AQS概览_第3张图片 MPP架构图示

 

可以将MMP理解为刀片服务器,每个刀扇里的都是一台独立SMP架构服务器,并且每个刀扇之间均有高性能的网络设备进行交互,保证smp服务器之间的数据传输性能。MMP架构比较依赖管理系统的处理能力来保障通信。

 

锁模型

CLH锁模型

是一种基于单向链表的、高性能、公平的自旋锁。申请加锁的线程通过前驱节点(pre-node)的变量进行自旋。当pre-node解锁后,当前节点会结束自旋并进行加锁。

CLH模型的逻辑:

  1. locked == true 表示节点处于加锁状态或者等待加锁状态。
  2. locked == false 表示节点处于解锁状态。
  3. 基于线程当前节点的前置节点的锁值(locked)进行自旋,前置节点的 locked == true 自旋;当前置节点解锁时,设置locked == false,后继节点(就是当前节点)监听到false,结束自旋。
  4. 每个节点在解锁时更新自己的锁值(locked),在这一时刻,该节点的后置节点会结束自旋,并进行加锁。
面试必考AQS-AQS概览_第4张图片 CLH模型的逻辑图示

 

由于自旋过程中,监控的是前置节点的变量,因此在SMP架构的共享内存模式,能更好的提供性能。

 

MCS锁模型

与CLH锁模型的最大区别是,监控的是自己的节点变量,当前置节点解锁后,会主动修改自己的节点变量状态。这种模型解决的是CLH模型在NUMA架构上的不足:当前置节点存在于其他CPU模块时,自旋会导致频繁的调用互联模块。是将自旋调整到了节点自身,互联模块的调用只存在于前置节点解锁的时刻。

MCS模型的逻辑:

  1. locked == false 标识节点处于加锁状态(没有自旋)
  2. locked == true 标识节点处于等待状态(自旋)
  3. 基于当前节点的锁值(locked)进行自旋,locked == true 自旋;当前置节点解锁时,修改后继节点(就是当前节点)的 locked == false ,进而结束当前节点的自旋。
  4. 每个节点在解锁时更新后继节点的锁值(locked),在这一刻,该节点的后置节点会结束自旋,并进行加锁。

 

面试必考AQS-AQS概览_第5张图片 MCS模型的逻辑图示

说了这么多,其实是想说明AQS中的链表,是为了实现上面的模型,它是针对CLH锁模型的一个变种。后面详细描述AQS中针对head和tail的操作,实际上就是在操作链表的入队和出队。所以说,AQS中的大部分方法,就是在实现CLH锁模型的逻辑。

 

AQS的功能

根据AQS的名称:抽象队列同步器,可以直白的知晓,

  1. 它是抽象类,自然有抽象方法。
  2. 它是一个队列同步器,这里的队列我们可以指定是个链表
  3. 同步器,则是通过对链表及资源的操作,达到同步指标的目的(注意是同步的指标,它不等同于同步)

对于第三点,之所以这样说,还有由于抽象类这个原因,从整体去看AQS,它的作用并不是去定义同步,而是去实现了一个CLH模型,直白点讲就是实现了如何操作队列及资源,至于何时达到同步,是由实现类去决定的。

由此可知:

  1. AQS中的实例方法:自身实现的用于操作队列以及资源。
  2. AQS中的抽象方法:交给子类实现,来决定同步状态。

 

尾声

本文只是简略的介绍了AQS的组成及每个成员的功能后续内容将会详细展开每个成员,深挖它们的内在逻辑。

 

推荐阅读

面试必考AQS-AQS概览

你可能感兴趣的:(JAVA源码,AQS,JUC,java)