当前位置: 首页 > news >正文

AbstractQueuedSynchronizer之AQS

在这里插入图片描述

目录

  • AQS简单入门
    • 为什么说AQS是JUC包下的重要基石
    • AQS能干嘛?
    • 实际实现原理
    • AQS自身成员变量
    • Node内部类的成员变量
    • 源码解读总结

AQS简单入门

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

整体就是一个抽象的FIFO队列来完成资源获取线程的排队工作,并通过一个int类变量表示持有锁的状态
在这里插入图片描述

为什么说AQS是JUC包下的重要基石

和AQS有关的类:

  • ReentrantLock
  • CountDownLatch
  • ReentrantReadWriteLock
  • Semaphore

  • 在这里插入图片描述
    都继承了AQS类

我们使用锁可能只是简单的lock和unlock,但是实际底层锁的实际逻辑,还是AQS来去执行的

AQS能干嘛?

有堵塞需要排队,实现排队的必需队列等候机制管理

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

实际实现原理

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

AQS自身成员变量

在这里插入图片描述

下图就是模拟AQS工作的一个流程图
在这里插入图片描述
head:头指针,头部出队
tail:尾指针,尾部入队
state:同步状态,判断是否阻塞

Node内部类的成员变量

在这里插入图片描述

由于我本地装的是jdk17,AQS与jdk8的源码有不一致情况,所以直接抠图给大家来看看Node的一些内部成员变量
在这里插入图片描述

源码解读总结

以ReentrantLock非公平锁为案例去进行lock和unlock的debug源码解读(jdk8情况下)

整个ReentrantLock加锁过程,分为三个阶段

一、尝试加锁
tryAcquire 方法,尝试获取锁,以下几种情况,会导致获取锁失败:
1、锁已经被其他线程续取;
2、锁没有被其他线程获取,但当前线程需要排队:
3、cas 失败(可能过程中已经有其他线程拿到锁了)
锁为自由状态(c==0),并不能说明可以立刻执行cas 获取锁,因为可能在当前线程获取锁之前,已经有其他线程在排队了,必须道循先来后到原则获取锁。所以还要调用hasQueuedPredecessors方法,查看自己是否需要排队

二、加锁失败,线程进入队列(这部分逻辑,是尝试获取锁失败的情况下,当前线程(尝试获取锁的)封装成 Node 对象,加入到aqs队列中的处理逻辑)
将当前线程封装成 Node对象,并加入排队队列中,根据排队队列是否执行过初始化,执行不同处理逻辑。
1、如果排队队列不为空,即之前已经初始化过了,此时只需将 新的 node加入排队队列未尾即可。
2、如果排队队列为空,需执行队列初始化。enq 会初始化一个 空的 Node,作为排队队列 的head,然后将需要排队的线程,作为head 的 next 节点插入。

三、线程入队列后,进入堵塞状态
1、首先判断 node 的前辈节点,是不是 head,如果是,说明它是下一个可以获得锁的线程,则调用一次tryAcquire,尝试获取锁,若获取到,则将链表关系重新维护下(node设置为 head,之前的 head从链表移出),然后返回。
2、如果 node 的前辈节点不是 head,或获取锁失败再判断其前辈节点的 waitState,是不是SIGNAL,如果是,则当前线程调用 park,进入阻塞状态,如不是:
1)==0,则设置为 SIGNAL;
2)>0(==1),则表示前辈节点已经被取消了,将取消的节点,从队列移出,重新维护下排队链表关系

然后再次进入 for 循环,上面的逻辑重新执行一遍,

就先说到这 \color{#008B8B}{ 就先说到这} 就先说到这
在下 A p o l l o \color{#008B8B}{在下Apollo} 在下Apollo
一个爱分享 J a v a 、生活的小人物, \color{#008B8B}{一个爱分享Java、生活的小人物,} 一个爱分享Java、生活的小人物,
咱们来日方长,有缘江湖再见,告辞! \color{#008B8B}{咱们来日方长,有缘江湖再见,告辞!} 咱们来日方长,有缘江湖再见,告辞!

在这里插入图片描述

http://www.lryc.cn/news/418061.html

相关文章:

  • <数据集>起重机识别数据集<目标检测>
  • 04--Docker
  • MiniCPM-V: A GPT-4V Level MLLM on Your Phone 手机上的 GPT-4V 级多模态大模型
  • Unity初识
  • 【游戏引擎之路】登神长阶(九)——《3D游戏编程大师技巧》:我想成为游戏之神!
  • Linux:线程同步之信号量
  • GPT-SoVITS-文本转语音(你的声音不再是唯一)
  • C语言深度剖析(部分)--剩下随缘更新
  • 计算机毕业设计选题推荐-电缆行业生产管理系统-Java/Python项目实战
  • Linux 下查看 CPU 使用率
  • 数理基础知识
  • Java解决lombok和mapstruct编译模块的问题
  • 大模型场景应用全集:持续更新中
  • 理解RabbitMQ中的消息存储机制:非持久化、持久化与惰性队列(Lazy Queue)
  • 【机器学习】BP神经网络正向计算
  • 谷粒商城实战笔记-108~109-elasticsearch删除与批量导入
  • RabbitMQ:发送者的可靠性之使用消息确认回调
  • HCIP学习 | OSPF---LSA限制、不规则区域、附录E、选路
  • CVE-2017-15715~Apache解析漏洞【春秋云境靶场渗透】
  • thinkphp 5.0.24生成模块
  • 值得注意!家里有带毛发动物就有浮毛?宠物空气净化器一键净化
  • Linux 代理(proxy)设置
  • 操作系统真相还原:获取文件属性
  • 聚鼎装饰画:投资一家装饰画店铺要花费多少钱
  • 编程的魅力、其重要性、学习方法以及未来趋势
  • ubuntu init set
  • MySQL数据分析进阶(八)存储过程
  • 最深的根,
  • 【常见的设计模式】工厂模式
  • postgres收缩工具两种工具的使用对比