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

【并发编程JUC】AQS详解

定义理解

AQS,全称为AbstractQueuedSynchronizer,是Java并发包(java.util.concurrent)中的一个框架级别的工具类,用于构建锁和同步器。它是许多同步类的基础,如ReentrantLock、Semaphore、CountDownLatch等,都是通过实现AQS的模板方法来实现其内部同步逻辑的。

  1. 同步状态:AQS使用一个volatile int类型的变量来表示同步状态,通过内置的FIFO(先进先出)队列(也称为CLH队列,一个虚拟的双向队列)来完成获取资源线程的排队工作。这个状态变量是线程共享的,用于表示同步资源的状态。
  2. CLH队列:CLH(Craig, Landin, and Hagersten)队列是AQS内部用于管理等待获取同步状态的线程的队列。它是一个虚拟的双向队列,即不存在队列实例,仅存在节点之间的关联关系。每个等待获取锁的线程都被封装成一个队列的节点(Node)。(将没有获取锁的线性封装成节点)
    在这里插入图片描述

理解锁和同步器的关系

  • 锁(Lock):锁是面向使用者的,它定义了使用者与锁交互的接口,比如允许两个线程并行访问某个资源,但隐藏了实现细节。锁是一个更高级的同步机制,它提供了比synchronized关键字更丰富的功能和灵活性。常见的锁实现有ReentrantLock等。
  • 同步器(AbstractQueuedSynchronizer, AQS):同步器是面向锁的实现者的,它简化了锁的实现方式,屏蔽了同步状态管理、线程的排队、等待与唤醒等底层操作。同步器是构建锁和其他同步组件的基础框架,通过提供一套模板方法,使得开发者能够轻松地实现自定义的同步逻辑。
  • 锁的实现依赖于同步器:在锁的实现中,通常会聚合同步器(AQS)来实现锁的语义。同步器为锁提供了必要的同步机制,如线程的排队、等待与唤醒等,从而简化了锁的实现复杂度。

AQS结构

在这里插入图片描述
梳理结构

  • Lock是Java并发包(java.util.concurrent.locks)中的一个接口
  • ReentrantLock是Lock接口的一个具体实现,它提供了可重入的互斥锁。
  • Sync是ReentrantLock中的一个内部抽象类,它继承自AbstractQueuedSynchronizer(AQS)。
  • FairSync是ReentrantLock中的一个内部类,它继承自Sync类。
  • NonfairSync同样是ReentrantLock的一个内部类,也继承自Sync类
  • AQS是Java并发包中的一个基础类,用于构建同步器(如锁和其他同步组件)。

Lock接口定义了锁的基本行为;ReentrantLock是Lock接口的一个具体实现,提供了可重入的互斥锁;Sync是ReentrantLock的内部抽象类,用于提供锁的基本实现机制;FairSync和NonfairSync是Sync的两个子类,分别实现了公平锁和非公平锁的逻辑;AQS则是ReentrantLock等同步器实现同步功能的基础。这些组件共同构成了Java并发包中强大的锁机制。

非公平锁源码如下:
在这里插入图片描述

公平锁源代码如下:
在这里插入图片描述

在这里插入图片描述
在非公平锁中,由于新到来的线程有可能直接尝试获取锁(而不需要排队),因此唤醒机制需要灵活处理。

模拟示例

在这里插入图片描述

假设有三个线程A、B、C都试图获取同一个ReentrantLock的锁(该锁以非公平模式配置)。
在这里插入图片描述

线程A的行为

  1. 尝试获取锁:线程A首先调用lock()方法,该方法内部会尝试通过compareAndSetState(0, 1)将锁的状态从0(未锁定)更改为1(锁定)。如果当前没有其他线程持有锁(即锁状态为0),则线程A成功获取锁。
  2. 执行业务逻辑:线程A在获取锁之后执行其业务逻辑。

线程B和C的行为(几乎同时)

当线程A持有锁时,线程B和C尝试获取锁。

  1. 调用acquire(1):线程B和C都调用acquire(1)方法,该方法是非公平锁获取锁的主要入口。
  2. 尝试非公平获取锁:acquire(1)内部调用tryAcquire(1),进而调用nonfairTryAcquire(1)。nonfairTryAcquire(1)首先检查当前锁状态是否为0(即未锁定),如果是,则尝试通过compareAndSetState(0, 1)获取锁。但由于线程A已经持有锁,所以B和C的这一步都会失败。(如果占用线程和当前线性为同一线程时,即为可重入锁
  3. 添加等待者:由于nonfairTryAcquire(1)返回false,线程B和C都会调用addWaiter()方法将自己封装成一个节点(Node),并通过enq(node)方法将节点加入到等待队列中。如果队列为空(即还没有其他线程在等待),则初始化头节点(head)并设置尾节点(tail)为新加入的节点。否则,将新节点添加到队尾。
  4. 进入等待队列并等待:线程B和C在加入等待队列后,会调用acquireQueued(node, 1)方法。在这个方法中,线程会进入一个自旋循环,不断检查前驱节点的状态,并尝试通过park()方法使自己进入等待状态(阻塞)。如果前驱节点的状态是SIGNAL(-1),则线程会通过LockSupport.park(this)被阻塞,直到被唤醒。

线程A释放锁

  1. 释放锁:当线程A完成其业务逻辑后,会调用unlock()方法来释放锁。这会将锁的状态从1改回0,并唤醒等待队列中的一个线程(如果有的话)。
  2. 唤醒等待线程:在释放锁的过程中,unlock()方法会调用LockSupport.unpark(thread)来唤醒等待队列中的一个线程。由于是非公平锁,被唤醒的线程不一定是等待时间最长的线程(即队列的头部线程)。

线程B或C被唤醒

被唤醒的线程(可能是B也可能是C,这取决于线程调度器的决策)会重新进入acquireQueued(node, 1)方法的自旋循环,并再次尝试获取锁。如果此时锁已被释放(即状态为0),则该线程可能会成功获取锁并退出自旋循环,继续执行其业务逻辑。

相关文章:

【并发编程JUC】AQS详解

定义理解 AQS,全称为AbstractQueuedSynchronizer,是Java并发包(java.util.concurrent)中的一个框架级别的工具类,用于构建锁和同步器。它是许多同步类的基础,如ReentrantLock、Semaphore、CountDownLatch等…...

如何找BMS算法、BMS软件的实习

之前一直忙,好久没有更新了,今天就来写一篇文章来介绍如何找BMS方向的实习,以及需要具备哪些条件,我的实习经历都是在读研阶段找的,读研期间两段的实习经历再加上最高影响因子9.4分的论文,我的秋招可以说是…...

AR视频技术与EasyDSS流媒体视频管理平台:打造沉浸式视频体验

随着增强现实(AR)技术的飞速发展,其在各个领域的应用日益广泛。这项技术通过实时计算摄影机影像的位置及角度,将虚拟信息叠加到真实世界中,为用户带来超越现实的感官体验。AR视频技术不仅极大地丰富了我们的视觉体验&a…...

每天一个数据分析题(三百九十九)- 逻辑回归

逻辑回归中,若选0.5作为阈值区分正负样本,其决策平面是( ) A. wxb= 0 B. wxb= 1 C. wxb= -1 D. wxb= 2 数据分析认证考试介绍:点击进入 题目来源于CDA模拟题库 点…...

【ARMv8/v9 GIC 系列 5.2 -- GIC 分组介绍:Group 0 |Group 1| Non-Secure Group 1】

请阅读【ARM GICv3/v4 实战学习 】 文章目录 GIC Interrupt grouping中断分组配置寄存器GIC 中断分组介绍Group 0(安全组0)Group 1(安全组1)Non-Secure Group 1(非安全组1)总结及例子GIC Interrupt grouping ARM GICv3 通过中断分组机制,与ARMv8异常模型和安全模型进行…...

前端代码规范 - 日志打印规范

在前端开发中,随着项目迭代升级,日志打印逐渐风格不一,合理的日志输出是监控应用状态、调试代码和跟踪用户行为的重要手段。一个好的日志系统能够帮助开发者快速定位问题,提高开发效率。本文将介绍如何在前端项目中制定日志输出规…...

C# 类型转换之显式和隐式

文章目录 1、显式类型转换2. 隐式类型转换3. 示例4. 类型转换的注意事项5. 类型转换的应用示例总结 在C#编程中,类型转换是一个核心概念,它允许我们在程序中处理不同类型的数据。类型转换可以分为两大类:显式类型转换(Explicit Ca…...

Ubuntu多显示器设置不同缩放比例

Ubuntu多显示器设置不同缩放比例 设备问题解决方案 设备 笔记本屏幕分辨率为2560 \times 1600,外接显示器的分辨率为3840 \times 2160。 问题 Ubuntu默认的显示器设置中,缩放仅能选择100%,200%,300%,400%。假…...

以太网协议介绍——UDP

注:需要先了解一些以太网的背景知识,方便更好理解UDP协议、 以太网基础知识一 以太网基础知识二 UDP协议 UDP即用户数据报协议,是一种面向无连接的传输层协议,属于 TCP/IP 协议簇的一种。UDP具有消耗资源少、通信效率高等优点&a…...

FFMpeg rtmp 无压缩推送本地yuv文件 压缩推送本地yuv文件

可以借鉴的&#xff1a;C使用FFmpeg实现YUV数据编码转视频文件_C 语言_脚本之家 yuv文件下载地址&#xff1a;YUV Sequences 无压缩的方式推送本地yuv文件 代码&#xff1a; #include <stdio.h> #include <unistd.h> #include <iostream> extern "C&…...

PostgreSQL LIMIT 子句

PostgreSQL LIMIT 子句 PostgreSQL 是一种功能强大的开源对象关系数据库管理系统&#xff0c;广泛用于各种应用中。在处理大量数据时&#xff0c;我们通常只需要检索部分记录&#xff0c;而不是整个数据集。这时&#xff0c;LIMIT 子句就变得非常有用。本文将详细介绍 Postgre…...

误删分区后的数据拯救:双管齐下恢复策略

在数字化时代&#xff0c;数据的价值日益凸显&#xff0c;而误删分区作为常见的数据安全威胁之一&#xff0c;常常让用户措手不及。本文将深入探讨误删分区的现象&#xff0c;并为您揭示两种高效的数据恢复方案&#xff0c;旨在帮助您在最短时间内找回失去的数据&#xff0c;同…...

git 添加本地分支, clean

//以develop为源创建本地分支fromdevelop git checkout -b fromdevelop git add . git commit -m "local" git checkout -b local/dev //切换到远程分支. git checkout dev git clean_git clean -f -d-CSDN博客 git clean -f -d #删除当前目录下没有被track…...

Linux:进程间通信(一.初识进程间通信、匿名管道与命名管道、共享内存)

上次结束了基础IO&#xff1a;Linux&#xff1a;基础IO&#xff08;三.软硬链接、动态库和静态库、动精态库的制作和加载&#xff09; 文章目录 1.认识进程间通信2.管道2.1匿名管道2.2pipe()函数 —创建匿名管道2.3匿名管道的四种情况2.4管道的特征 3.基于管道的进程池设计4.命…...

QML-各类布局

Colunm布局 Column{id:colspacing: 30Repeater{id:repmodel: ListModel{}Button{width: 100height: 50text: "btn"index}}//开始时候移动move: Transition {NumberAnimation { properties: "x,y"; easing.type: Easing.OutBounce }}//添加时变化add:Transi…...

el-table封装点击列筛选行数据功能,支持筛选,搜索,排序功能

数据少的话&#xff0c;可以前端实现&#xff0c;如果多的话&#xff0c;建议还是请求接口比较合理父组件&#xff1a; <template> <div class"home"> <!-- <img alt"Vue logo" src"../assets/logo.png"> <HelloWorld …...

【SpringBoot3学习 | 第1篇】SpringBoot3介绍与配置文件

文章目录 前言 一. SpringBoot3介绍1.1 SpringBoot项目创建1. 创建Maven工程2. 添加依赖(springboot父工程依赖 , web启动器依赖)3. 编写启动引导类(springboot项目运行的入口)4. 编写处理器Controller5. 启动项目 1.2 项目理解1. 依赖不需要写版本原因2. 启动器(Starter)3. Sp…...

SpringBoot整合Dubbo的快速使用教程

目录 一、什么是Dubbo? 二、SpringBoot整合Dubbo 1、父工程引入依赖 2、各个Dubbo服务子模块引入依赖 3、服务提供者 &#xff08;1&#xff09;启动类添加注解EnableDubbo &#xff08;2&#xff09;服务类添加注解DubboService &#xff08;3&#xff09;配置文件…...

昇思25天学习打卡营第12天| 基于MindNLP+MusicGen生成自己的个性化音乐

之前都是看图文类的东西&#xff0c;今天体验一点不一样的。来点听力的内容。 mindspore有音乐生成模型MusicGen&#xff0c;MusicGen支持两种生成模式&#xff1a;贪心&#xff08;greedy&#xff09;和采样&#xff08;sampling&#xff09;。在实际执行过程中&#xff0c;采…...

代理设计模式和装饰器设计模式的区别

代理设计模式: 作用:为目标(原始对象)增加功能(额外功能,拓展功能) 三种经典应用场景: 1&#xff1a;给原始对象增加额外功能(spring添加事务,Mybatis通过代理实现缓存功能等等) 2&#xff1a;远程代理&#xff08;网络通信&#xff0c;输出传输&#xff08;RPC&#xff0c;D…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

Modbus RTU与Modbus TCP详解指南

目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...