【JUC】三十、什么是AQS

2023-12-15 20:35:47

0、背景

一段常见的代码:

Lock lock = new ReentrantLock();
lock.lock;
try{
	//do Something
} finally{
	lock.unlock();
}

简单的一个加锁解锁,多线程来抢锁,抢不到锁的线程被分配到哪儿去了?放到一个队列中,后续再出对入队?队列底层又是怎么维护的?

1、AQS介绍

AQS,即AbstractQueuedSynchronizer,抽象的队列同步器。AQS是JUC的基石,好比JVM之于Java。

AQS是用来实现锁或者其它同步器组件的公共基础部分的抽象实现, 是重量级基础框架及整个JUC体系的基石,主要用于解决锁分配给"谁"的问题

AQS相关类是:

在这里插入图片描述

  • AbstractOwnableSynchronizer(下面两兄弟的父类)
  • AbstractQueuedLongSynchronizer:since1.6
  • AbstractQueuedSynchronizer:简称AQS,since1.5

三者都是抽象类。(抽象类,相比接口的全抽象,属半抽象,完成了一部分逻辑,剩余一部分定义了方法规范,给子类去继承和重写)

2、AQS核心概念

以下是AQS类的解释,关键词:先进先出的一个队列 + state状态值

在这里插入图片描述

类比人(线程)去银行(共享资源对象)排队办理业务,有人到窗口开始办时,指示灯变红(state=1,getState、setState),代表有人,其余人去候客区的椅子上等着:

在这里插入图片描述

这个候客区,整体就是一个抽象的FIFO队列来完成对获取资源线程的排队工作,并通过一个int类变量表示持有锁的状态

在这里插入图片描述

这个抽象队列,称为CLH队列,CLH即Craig、Landin and Hagersten,是三个人名,是一个单向链表,但AQS中的队列是CLH变体的虚拟双向队列FIFO,等待的线程就进入这个队列。

3、AQS是JUC的基石

之所以成AQS是JUC的基石,是因为JUC的很多东西底层都是通过AQS实现的,如图:

在这里插入图片描述

举个例子,比如ReentrantLock:

在这里插入图片描述

4、锁和同步器的关系

锁:

  • 面向普通开发者,给开发者用的
  • 定义了开发者和锁交互使用的API,比如lock、unlock,隐藏了实现细节,调用即可

同步器:

  • 面向锁的实现者,Java并发的缔造者
  • 提出统一规范并简化了锁的实现,屏蔽了同步状态管理、同步队列的管理和维护、阻塞线程排队和通知、唤醒机制等公共的底层细节,将其抽象出来,形成抽象的公共基类,做为一切锁和同步组件实现的公共基础部分

5、AQS的作用

加锁会导致阻塞,有阻塞,抢不到的线程就需要排队,实现排队必然需要队列。类比银行办理业务的窗口满了,其他人去候客区等待,但等待的线程仍然保留了获取锁的可能,且获取锁的流程仍在继续(候客区的顾客也在等着被叫到号)。

在这里插入图片描述

如果共享资源被占用,就需要一定的阻塞、唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中,这个队列就是AQS同步队列的抽象表现。它将要请求共享资源的线程及自身的等待状态封装成队列的结点对象 Node(候客区的一把把椅子),通过CAS自旋以及LockSupport.park()的方式,维护state变量的状态,使并发达到同步的效果。

在这里插入图片描述

AQS使用一个volatile的int类型的成员变量state来表示同步状态,通过内置的FIFO队列来完成资源获取的排队工作,将每个要去抢占资源的线程封装成一个Node节点来实现锁的分配,通过CAS完成对State值的修改。

在这里插入图片描述

6、state和CLH队列

AQS类、Node类以及JUC相关类的关联关系如下:

在这里插入图片描述

AQS类,有个int类型的成员变量state:

private volatile int state;

它就类似去银行办理业务的受理窗口状态。0就是没人,自由状态可办理,大于等于1就是有人占用窗口,其他人坐在候客区(队列)的椅子上(Node)等着去。而CLH队列,一个双向队列,就是候客区,队列中装的就是一个个Node内部类的对象。

在这里插入图片描述

总结:AQS的实质就是CLH的双端队列,加一个state变量,队列中排队的每个个体就是一个Node。

6、AQS的内部类Node

,Node也有一个属性,waitState,和state是两个东西

银行候客区的椅子,每个椅子做一个排队的请求线程
在这里插入图片描述
在这里插入图片描述
共享型的还是独占型的

在这里插入图片描述

1,即排队在Node里的线程不想排了,
-2:即后续线程需要被唤醒
-3:线程正在condition里面等待
-3:传播、广播、一块儿的全部通知
在这里插入图片描述

Node这个内部类的成员变量,代表Node里面线程的等待状态,其取值不同,后面的出队入队也就跟着受影响
在这里插入图片描述
当前Node节点的前置、后置节点,坐Node里的线程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

文章来源:https://blog.csdn.net/llg___/article/details/135003742
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。