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

从源码解析AQS

前置概念

要彻底了解AQS的底层实现就必须要了解一下线程相关的知识。
包括voliate

voliate

我们使用翻译软件翻译一下volatile,会发现它有以下几个意思:易变的;无定性的;无常性的;可能急剧波动的;不稳定的;易恶化的;易挥发的;易发散的。这也正式使用volatile关键字的语义。

当你使用volatile去申明个变量时,就等于告诉了虚拟机,这个变量极有可能会被其他程序或者线程修改。为了确保这个变量被修改后,应用程序范围内所有线程都能够“看到”这个改动,虚拟机就必须采用一些特殊手段,保证这个变量的可见性等特点
比如,根据编译器的优化规则,如果不使用volatile申明变量,这个变量被修改后其他线程可能并不会被通知到,甚至在别的线程中,看到变量的修改程序都是反的。但是使用volatile,虚拟机就会谨慎的处理这种情况

CAS

CAS 是高并发的一个重要的编程实现,即compareAndSet,对比并且设置。

意思就是说,要做一个修改就必须先教研我改之前的期望值是否和他现在的是否相同,如果相同则修改,不相同则不处理。

什么是AQS

AQS的本质是java中的AbstractQueuedSynchronizer类。
AQS是并发包下的一个基类,基于它实现的类包括CountDownLatch,ReentranLock…

下面我们就以ReentranLock为入口详细讲解下AQS

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {static final class Node {/** 用于指示节点正在共享模式下等待的标记 */static final Node SHARED = new Node();/** 用于指示节点正在以独占模式等待的标记 */static final Node EXCLUSIVE = null;/** waitStatus 值,用于指示线程已取消 */static final int CANCELLED =  1;/** waitStatus 值,用于指示后续线程需要取消停放 */static final int SIGNAL    = -1;/** waitStatus 值,用于指示线程正在等待条件 */static final int CONDITION = -2;/** waitStatus 值来指示下一个 acquireShared 应无条件传播 */static final int PROPAGATE = -3;/** * 状态字段,仅采用以下值: * 信号:此节点的后继节点被(或即将)阻止(通过 park),因此当前节点在释放或取消时必须取消其后继节点的停放。为了避免争用,acquire 方法必须首先指示它们需要一个信号,然后重试原子获取,然后在失败时阻止。* CANCELLED:该节点因超时或中断而取消。节点永远不会离开此状态。特别是,具有已取消节点的线程永远不会再次阻塞。条件:此节点当前位于条件队列中。在传输之前,它不会用作同步队列节点,此时状态将设置为 0。(此处使用此值与该字段的其他用途无关,但简化了机制。* 传播:应将 releaseShared 传播到其他节点。这是在 doReleaseShared 中设置的(仅适用于头节点),以确保传播继续进行,即使其他操作此后进行了干预。* 0:以上都不是 为了简化使用,这些值以数字形式排列。非负值表示节点不需要发出信号。因此,大多数代码不需要检查特定值,只需检查符号即可。对于正常同步节点,该字段初始化为 0,对于条件节点,该字段初始化为 CONDITION。它使用 CAS 进行修改(或者在可能的情况下,无条件易失性写入)。*/volatile int waitStatus;/*** 上一个节点*/volatile Node prev;/*** 下一个节点*/volatile Node next;/*** 将此节点排队的线程。在构造时初始化,使用后清空。*/volatile Thread thread;/*** 链接到下一个节点,等待条件,或特殊值 SHARED。* 因为条件队列只有在以独占模式保持时才会被访问,所以我们只需要一个简单的链接队列来在节点等待条件时保存它们。* 然后,它们被转移到队列中以重新获取。由于条件只能是独占的,因此我们通过使用特殊值来保存字段来指示共享模式。*/Node nextWaiter;/*** 如果节点在共享模式下等待,则返回 true*/final boolean isShared() {return nextWaiter == SHARED;}/*** 返回上一个节点,如果为 null,则引发 NullPointerException。* 当 predecessor 不能为 null 时使用。可以省略 null 检查,但存在该检查以帮助 VM。* 返回:此节点的前身*/final Node predecessor() throws NullPointerException {Node p = prev;if (p == null)throw new NullPointerException();elsereturn p;}Node() {    // Used to establish initial head or SHARED marker}Node(Thread thread, Node mode) {     // Used by addWaiterthis.nextWaiter = mode;this.thread = thread;}Node(Thread thread, int waitStatus) { // Used by Conditionthis.waitStatus = waitStatus;this.thread = thread;}}/*** 头节点*/private transient volatile Node head;/*** 尾节点*/private transient volatile Node tail;/*** 状态*/private volatile int state;
}
ReentranLock
acquire
 /*** 以独占模式获取,忽略中断。通过至少调用一次 tryAcquire来实现,成功返回。* 否则,线程会排队,可能会反复阻塞和解除阻塞,调用 tryAcquire 直到成功。此方法可用于实现方法Lock.lock。* 参数:arg – acquire 参数。此值被传达给 tryAcquire ,但以其他方式未解释,可以表示您喜欢的任何内容。*/public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}
tryAcquire
/*** 1. 获取当前线程 * 2. 获取当前锁状态c * 3. 如果当前锁状态为0,则判断是否有排队的前任线程,并尝试使用compareAndSetState方法将锁状态设置为acquires,如果成功则将当前线程设置为独占所有者并返回true * 4. 如果当前锁状态不为0且当前线程已经是独占所有者,则计算新的锁状态nextc,如果nextc小于0,则抛出异常"Maximum lock count exceeded",否则更新锁状态为nextc并返回true * 5. 如果以上条件都不满足,则返回false。*/
protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() &&// 用CAS的方式设置状态compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {//1. 首先,代码检查当前线程是否为独占锁的拥有者,如果是则执行以下操作: //2. 计算下一个锁的状态值 nextc = c + acquires; //3. 如果下一个状态值小于0,则抛出错误 "Maximum lock count exceeded"; //4. 设置锁的状态为 nextc; //5. 返回 true 表示成功获取独占锁。int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;
}//判断当前线程前面是否还有其他线程在等待。 
public final boolean hasQueuedPredecessors() {Node t = tail;Node h = head;Node s;return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());
}
//设置线程作为独占所有者线程。
protected final void setExclusiveOwnerThread(Thread thread) {exclusiveOwnerThread = thread;
}
addWaiter
/*** 这段代码的作用是向一个链表中添加一个等待节点。 * 1. 创建一个新的节点,将当前线程和传入的模式作为参数。 * 2. 尝试使用快速路径添加节点到链表的末尾,如果失败则备用完整的添加方法。 * 3. 获取当前尾节点作为前驱节点。 * 4. 如果前驱节点不为空,则设置新节点的前驱为前驱节点。 * 5. 如果成功将新节点设置为尾节点,则将前驱节点的后继指向新节点,然后返回新节点。 * 6. 如果无法使用快速路径,则调用enq方法完整添加节点到链表末尾,并返回新节点。*/
private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);// Try the fast path of enq; backup to full enq on failureNode pred = tail;if (pred != null) {node.prev = pred;// 用CAS的方式设置尾部节点if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}enq(node);return node;
}
acquireQueued
//以独占不间断模式获取已在队列中的线程。由条件等待方法以及获取使用
final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {// 进入一个无限循环,不断尝试获取锁。 // 1.在循环中,首先获取前驱节点p。 // 2. 如果p是头结点并且tryAcquire(arg)成功获取到锁,则将当前节点设置为头结点,断开p的next引用,将failed设为false,然后返回interrupted的值。 // 3. 如果无法获取锁,则判断是否应该在获取失败后阻塞线程,并检查是否被中断。 // 4. 如果被中断,则将interrupted设为true。final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&// 中断线程,放入等待队列parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)// 取消竞争锁cancelAcquire(node);}
}//判断在获取锁失败后是否需要进行阻塞等待。这是所有采集环路中的主要信号控制。需要 pred == node.prev。private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {//1. 首先,获取前驱节点的等待状态int ws = pred.waitStatus;//2. 如果等待状态(ws)等于Node.SIGNAL,表示前驱节点已经设置了状态要求释放锁以发信号通知当前节点可以安全地阻塞等待,返回true。 if (ws == Node.SIGNAL)/** This node has already set status asking a release* to signal it, so it can safely park.*/return true;//3. 如果等待状态(ws)大于0,表示前驱节点已取消,需要跳过前驱节点并指示重试。在循环中,将当前节点的prev指向前驱节点的prev,直到找到等待状态不大于0的前驱节点,然后将前驱节点的next指向当前节点。 if (ws > 0) {//4. 如果等待状态(ws)为0或PROPAGATE,则表示需要一个信号,但暂时不阻塞等待。调用者将需要重试以确保在阻塞等待之前不能获取锁。 do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);pred.next = node;} else {// 用CAS的方式设置等待状态compareAndSetWaitStatus(pred, ws, Node.SIGNAL);}//5. 最后返回false,表示不需要阻塞等待。return false;
}

相关文章:

从源码解析AQS

前置概念 要彻底了解AQS的底层实现就必须要了解一下线程相关的知识。 包括voliatevoliate 我们使用翻译软件翻译一下volatile&#xff0c;会发现它有以下几个意思&#xff1a;易变的;无定性的;无常性的;可能急剧波动的;不稳定的;易恶化的;易挥发的;易发散的。这也正式使用vola…...

基于Spring Boot的云上水果超市的设计与实现

摘 要 伴随着我国社会的发展&#xff0c;人民生活质量日益提高。于是对云上水果超市进行规范而严格是十分有必要的&#xff0c;所以许许多多的信息管理系统应运而生。此时单靠人力应对这些事务就显得有些力不从心了。所以本论文将设计一套云上水果超市&#xff0c;帮助商家进行…...

游戏引擎中的动画基础

一、动画技术简介 视觉残留理论 - 影像在我们的视网膜上残留1/24s。 游戏中动画面临的挑战&#xff1a; 交互&#xff1a;游戏中的玩家动画需要和场景中的物体进行交互。实时&#xff1a;最慢需要在1/30秒内算完所有的场景渲染和动画数据。&#xff08;可以用动画压缩解决&am…...

springboot3快速入门案例2024最新版

前边 springboot3 系统要求 技术&工具版本&#xff08;or later&#xff09;maven3.6.3 or later 3.6.3 或更高版本Tomcat10.0Servlet9.0JDK17 SpringBoot的主要目标是&#xff1a; 为所有 Spring 开发提供更快速、可广泛访问的入门体验。开箱即用&#xff0c;设置合理的…...

软考 系统架构设计师系列知识点之系统性能(1)

所属章节&#xff1a; 第2章. 计算机系统基础知识 第9节. 系统性能 系统性能是一个系统提供给用户的所有性能指标的集合。它既包括硬件性能&#xff08;如处理器主频、存储器容量、通信带宽等&#xff09;和软件性能&#xff08;如上下文切换、延迟、执行时间等&#xff09;&a…...

Trent-FPGA硬件设计课程

本课程涵盖FPGA硬件设计的基础概念和实践应用。学生将学习Verilog语言编程、数字电路设计原理、FPGA架构和开发工具的使用。通过项目实践&#xff0c;掌握FPGA设计流程和调试技巧&#xff0c;为硬件加速和嵌入式系统开发打下坚实基础。 课程大小&#xff1a;4.3G 课程下载&am…...

【大模型学习记录】db-gpt源码安装问题汇总

1、首次源码安装时安装的其实dbgpt到conda环境中&#xff0c;会将路径一起安装。 如果有其他的路径使用同样的conda环境会报错&#xff0c;一直读取的就是原先的路径的内容。需要自己新创建一个conda env 2、界面中配置知识库问答时&#xff0c;报错 # 1、报的错如下&#x…...

QB PHP 多语言配置

1&#xff1a; 下载QBfast .exe 的文件 2&#xff1a; 安装的时候 &#xff0c;一定点击 仅为我 安装 而不是 所有人 3&#xff1a; 如果提示 更新就 更新 &#xff0c; 安装如2 4&#xff1a; 如果遇到 新增 或者编辑已经 配置的项目时 不起作用 &#xff1a; 右…...

Kubernetes实战(三十一)-使用开源CEPH作为后端StorageClass

1 引言 K8S在1.13版本开始支持使用Ceph作为StorageClass。其中云原生存储Rook和开源Ceph应用都非常广泛。本文主要介绍K8S如何对接开源Ceph使用RBD卷。 K8S对接Ceph的技术栈如下图所示。K8S主要通过容器存储接口CSI和Ceph进行交互。 Ceph官方文档&#xff1a;Block Devices a…...

【Python爬虫】详解BeautifulSoup()及其方法

文章目录 &#x1f354;准备工作&#x1f339;BeautifulSoup()⭐代码实现✨打印标签里面的内容✨快速拿到一个标签里的属性✨打印整个文档&#x1f386;获取特定标签的特定内容 &#x1f339;查找标签&#x1f388;在文档查找标签 find_all&#x1f388;正则表达式搜索 &#x…...

C语言经典算法-8

文章目录 其他经典例题跳转链接41.基数排序法42.循序搜寻法&#xff08;使用卫兵&#xff09;43.二分搜寻法&#xff08;搜寻原则的代表&#xff09;44.插补搜寻法45.费氏搜寻法 其他经典例题跳转链接 C语言经典算法-1 1.汉若塔 2. 费式数列 3. 巴斯卡三角形 4. 三色棋 5. 老鼠…...

Panasonic松下PLC如何数据采集?如何实现快速接入IIOT云平台?

在工业自动化领域&#xff0c;数据采集与远程控制是提升生产效率、优化资源配置的关键环节。对于使用Panasonic松下PLC的用户来说&#xff0c;如何实现高效、稳定的数据采集&#xff0c;并快速接入IIOT云平台&#xff0c;是摆在他们面前的重要课题。HiWoo Box工业物联网关以其强…...

高性能 MySQL 第四版(GPT 重译)(四)

第十一章&#xff1a;扩展 MySQL 在个人项目中运行 MySQL&#xff0c;甚至在年轻公司中运行 MySQL&#xff0c;与在市&#xfffd;&#xfffd;已经建立并且“呈现指数增长”业务中运行 MySQL 大不相同。在高速业务环境中&#xff0c;流量可能每年增长数倍&#xff0c;环境变得…...

整型数组按个位值排序 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 给定一个非空数组(列表)&#xff0c;其元素数据类型为整型&#xff0c;请按照数组元素十进制最低位从小到大进行排序&#xff0c;十进制最低位相同的元素&#xf…...

【React】Diff算法

1. React15 Diff算法&#xff08;递归进行&#xff09; 一句话概括&#xff1a;新虚拟DOM和旧虚拟DOM对比&#xff0c;找出差异&#xff0c;根据差异更新真实DOM Diff过程描述&#xff1a; 1. 树比较(DOM) 同层节点之间相互比较&#xff0c;不会跨层级比较。&#xff08;当发现…...

【物联网】Modbus 协议及应用

Modbus 协议简介 QingHub设计器在设计物联网数据采集时不可避免的需要针对Modbus协议的设备做相关数据采集&#xff0c;这里就我们的实际项目经验分享Modbus协议 简介 Modbus由MODICON公司于1979年开发&#xff0c;是一种工业现场总线协议标准。1996年施耐德公司推出基于以太…...

Docker容器引擎

1、Docker是什么。 Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的"虚拟机"。Docker的logo设计为蓝色鲸鱼&#xff0c;拖着许多集装箱。鲸鱼可以看作宿主机&#xff0c;而集装箱可以理解为相互隔离的容器&#xff0c;每个集装箱中都包含自己的应…...

2.28线程

注意被抢占时是返回原队列&#xff0c;优先级不变。越往下优先级越小。往下没有优先级时&#xff0c;在最低的优先级队列里循环 到达了不一定会被服务&#xff0c;会进入就绪态进行等待 。核心等式就是周转时间运行时间等待时间&#xff0c;带权就是周转/运行&#xff0c; 随着…...

TCP/IP ⽹络模型

TCP/IP ⽹络模型 对于同⼀台设备上的进程间通信&#xff0c;有很多种⽅式&#xff0c;⽐如有管道、消息队列、共享内存、信号等⽅式&#xff0c;⽽对于不同设备上的进程间通信&#xff0c;就需要⽹络通信&#xff0c;⽽设备是多样性的&#xff0c;所以要兼容多种多样的设备&am…...

云原生:重塑未来应用的基石

随着数字化时代的不断深入&#xff0c;云原生已经成为了IT领域的热门话题。它代表着一种全新的软件开发和部署范式&#xff0c;旨在充分利用云计算的优势&#xff0c;并为企业带来更大的灵活性、可靠性和效率。今天我们就来聊一聊这个热门的话题&#xff1a;云原生~ &#x1f4…...

蓝桥杯day4刷题日记

P8605 [蓝桥杯 2013 国 AC] 网络寻路 思路来源于https://www.luogu.com.cn/article/iat8irsf #include <iostream> using namespace std; int n,m; int q[10010]; int v[100010],u[100010]; long long res;int main() {cin>>n>>m;for(int i0;i<m;i){cin…...

[Qt学习笔记]Qt下使用Halcon实现采图时自动对焦的功能(Brenner梯度法)

目录 1、介绍2、实现方法2.1 算法实现过程2.2 模拟采集流程 3、总结4、代码展示 1、介绍 在机器视觉的开发中&#xff0c;现在有很多通过电机去做相机的聚焦调节&#xff0c;对比手工调节&#xff0c;自动调节效果更好&#xff0c;而且其也能满足设备自动的需求&#xff0c;尤…...

常州IGM机器人RTE497的日常维修保养方法

一、IGM机器人RTE497日常检查 每日工作前&#xff0c;进行以下检查&#xff1a; 外观检查&#xff1a;确认IGM机器人RTE497本体无明显损伤&#xff0c;各部件连接稳固。 电缆检查&#xff1a;检查所有电缆、气管等是否完好&#xff0c;无磨损、无挤压。 润滑检查&#xff1a;确…...

如何利用机器学习和Python编写预测模型来预测设备故障

预测设备故障是机器学习和数据科学的一个常见问题&#xff0c;通常可以通过以下几个步骤来解决&#xff1a; 1. 数据收集 首先&#xff0c;需要收集与设备运行相关的数据&#xff0c;包括&#xff1a; 设备的历史数据环境数据&#xff08;如温度、湿度等&#xff09;使用时间…...

mysql部署(2)主从复制

在前面的基础上&#xff0c;现有26、41两个mysql8的实例&#xff0c;下面以26为主41为从搭建主从复制&#xff1a; 机器主从端口号root密码主从复制账号密码xxx.xx.xxx.26主3306Mysql#26user1/user1#26xxx.xx.xxx.41从3306Mysql#41 一、master主库配置 1、修改mysql配置文件…...

FX-数组的使用

1一维数组 1.1一维数组的创建和初始化 1.1.1数组的创建 //代码1 int arr1[10]; char arr2[10]; float arr3[1]; double arr4[20]; //代码2 //用宏定义的方式 #define X 3 int arr5[X]; //代码3 //错误使用 int count 10; int arr6[count];//数组时候可以正常创建&#xff1…...

springboot283图书商城管理系统

图书商城管理系统 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本图书商城管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理…...

FFmpeg-- c++实现:音频流aac和视频流h264封装

文章目录 流程api核心代码muxer.hmuxer.cpp aac 和 h264 封装为视频流&#xff0c;封装为c的Muxter类 流程 分配视频文件上下文 int Init(const char *url); 创建流&#xff0c;赋值给视频的音频流和视频流 int AddStream(AVCodecContext *codec_ctx); 写视频流的head int Se…...

单片机烧录方式,JTAG,ISP,SWD,

常见的词汇 参考 ISP&#xff1a;In System Programing&#xff0c;在系统编程 IAP&#xff1a;In Application Programing&#xff0c;在应用编程 ICP&#xff1a;In Circuit Programing&#xff0c;在电路编程 ICSP全称是In Circuit Serial Programming JTAG(Joint Test Act…...

【项目管理后台】Vue3+Ts+Sass实战框架搭建一

项目管理后台 建立项目最好是卸载Vetur 新建.env.d.ts文件安装Eslint安装校验忽略文件添加运行脚本 安装prettier新建.prettierrc.json添加规则新建.prettierignore忽略文件 安装配置stylelint新建.stylelintrc.cjs 添加后的运行脚本配置husky配置commitlint配置husky 强制使用…...

辽宁建设工程信息网打不开/广西网络优化seo

最近一直忙于一个服装电商系统的开发&#xff0c;下午准备回忆下14年和15年开发P2P网贷系统时的资金账务系统&#xff0c;以便用到电商系统中来的。 这套简洁实用的资金账务系统&#xff0c;在我看来&#xff0c;非常能说明&#xff0c;使我想阐述一个观点&#xff0c;“定义…...

做企业网站什么软件好/百度下载官方下载安装

各种媒体是我们获取当今时代信息的一个最重要途径。公元前&#xff0c;报纸就已经 出现&#xff0c;当时是将一些信息记录在白色的板子上。随着时代发展&#xff0c;纸媒逐渐被其他 一些媒体所取代&#xff0c;比如工业时代&#xff0c;很多人就将信息新闻的获取途径从纸媒转换…...

wordpress博客优化/网络营销师报名官网

deb软件包管理流行的两种软件包管理机制软件包的类型软件包的命名软件包管理工具分类dpkg相关命令dpkg和apt软件包管理器有什么区别&#xff1f;APT工作原理APT软件源配置文件软件源刷新软件源软件管理相关命令修复软件包依赖关系安装软件包卸载软件包软件包信息的查询流行的两…...

广东省住房和城乡建设网站/网站网络推广优化

http://mysqlserverteam.com/...

怎样做3d动画短视频网站/深圳网站设计十年乐云seo

Java架构师的自我修养&#xff1a;Java架构师常见的面试题有哪些&#xff1f;下面和千锋广州小编一起来看看吧&#xff01; 基础题目 Java线程的状态 进程和线程的区别&#xff0c;进程间如何通讯&#xff0c;线程间如何通讯 HashMap的数据结构是什么?如何实现的。和HashT…...

广东省住房和城乡建设厅网站/郑州推广优化公司

Spring MVC整合SpringBoot提供为整合MVC框架提供的功能特性内置两个视图解析器&#xff1a;ContentNegotiatingViewResolver和BeanNameViewResolver支持静态资源以及WebJars自动注册了转换器和格式化器支持Http消息转换器自动注册了消息代码解析器支持静态项目首页index.html支…...