JUC 体系的基石——AQS
—— AQS(AbstractQueuedSynchronizer)
概念
- 抽象队列同步器;volatile + cas 机制实现的锁模板,保证了代码的同步性和可见性,而 AQS 封装了线程阻塞等待挂起,解锁唤醒其他线程的逻辑。AQS 子类只需要根据状态变量,判断是否可获取锁,是否释放锁,使用 LockSupport 挂起、唤醒线程即可
- 定义:是用来实现锁或者其他同步器组件的公共基础部分的抽象实现,是重量级基础框架及整个 JUC 体系的基石,主要用于解决锁分配的问题
- 官网:为实现阻塞锁和相关的同步器提供一个框架,依赖于先进先出的一个等待;依靠单个原子 int 值来表示状态,通过占用和释放方法,改变状态值
- 整体就是一个抽象的 FIFO 队列来完成资源获取线程的排队工作,并通过一个 volatile 的 int 类型变量(state)表示持有锁的状态
- CLH(Craig、Landin、Hagersten)队列,是一个单向链表,AQS 中的队列是 CLH 变体的虚拟双向队列 FIFO

为什么 AQS 是 JUC 中最重要的基石?
- ReentrantLock 、CountDownLatch、ReentrantReadWriteLock、Semaphore 等都与 AQS 有关
- 锁 和 同步器的关系
- 锁是面向锁的使用者,定义了程序员和锁交互的使用层 API,隐藏了实现细节
- 同步器是面向锁的实现,DougLee 提出统一规范并简化了锁的实现,将其抽象出来,屏蔽了同步状态管理、同步队列的管理和维护、阻塞线程排队和通知、唤醒机制等,是一切锁和同步组件实现的公共基础部分
作用
- 多个线程抢占共享资源,只有一个线程抢占成功,其他线程必然涉及一种排队等候机制
- 如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是 CLH 队列的变体实现,将暂时获取不到锁的线程加入到队列中,这个队列就是 AQS 同步队列的抽象表现。它将要请求共享资源的线程及自身的等待状态封装成队列的节点对象(Node),通过 CAS、自旋以及 LockSupport.park() 的方式,维护 state 变量的状态,使并发达到同步的效果
ReentrantLock

- 公平锁 和 非公平锁的 lock() 方法唯一的区别在获取同步状态时多了一个限制条件
hasQueuedPredecessors(),这是公平锁加锁时判断等待队列中是否存在有效节点的方法
源码分析
- 整个 ReentrantLock 的加锁过程,可以分为三个阶段
- 尝试加锁:
tryAcquire()

- 当出现 锁已经被其他线程获取 / 锁没有被其他线程获取,但当前线程需要排队 / cas 失败 这三种情况时,会导致获取锁失败
- 锁为自由状态,并不能说明可以立刻执行 cas 获取锁,因为可能在当前线程获取锁之前,已经有其他线程在排队了,必须 遵循先来后到的原则获取锁。还要调用
hasQueuedPredecessors()方法,查看自己是否需要排队
-
加锁失败,线程进入队列:
acquireQueued()

-
线程入队列后,进入阻塞状态:
addWaiter()

- 尝试加锁:
- 具体细节查看源码
—— ReentrantReadWriteLock(可重入读写锁)
概念
- 读写锁定义:一个资源能够被多个读线程访问,或者被一个写线程访问,但是不能同时存在读写线程(读写互斥、读读共享);只有在读多写少的情景之下,读写锁才具有较高的性能表现
- 缺点:
- 写锁饥饿问题:出现大面积读锁,只有几个写锁,存在写锁长时间抢占不到锁的情况
- 锁降级:将写锁降级为读锁;锁的严苛程度变强叫升级,反之叫降级
- 如果同一个线程持有了写锁,在没有释放写锁的情况下,它还可以继续获得读锁。这就是写锁的降级,降级成了读锁
- 遵循 获取写锁——》获取读锁——》释放写锁——》释放读锁 的次序,可以实现锁降级;反之,读锁升级到写锁是不可能的
- 如果有线程在读,未释放读锁前,则该线程是无法获取写锁的,是悲观锁的策略
- 锁降级源码总结:


—— StampedLock(邮戳锁)
概念
- StampedLock 是 JDK1.8 中新增的一个读写锁,也是对 JDK1.5 中的读写锁 ReentrantReadWriteLock的优化
- stamp(戳记,long类型):代表了锁的状态。当stamp返回 0 时,表示线程获取锁失败。并且,当释放锁或者转换锁的时候,都要传入最初获取的stamp值
- 使用乐观锁策略,可以解决 ReentrantReadWriteLock 锁饥饿的问题(使用公平锁策略一定程度上也可以缓解,但是需要以牺牲系统吞吐量为代价)
- StampedLock 对短的只读代码段,使用乐观模式通常可以减少争用并提高吞吐量
缺点
- StampedLock 不支持重入,没有 Re 开头
- StampedLock 的悲观读锁和写锁都不支持条件变量(Condition)
- 使用 StampedLock 一定不要中断操作,即不要调用 interrupt() 方法
正常情况下,ReentrantLock 和 ReentrantReadWriteLock 业务场景还是较多
相关文章:
JUC 体系的基石——AQS
—— AQS(AbstractQueuedSynchronizer) 概念 抽象队列同步器;volatile cas 机制实现的锁模板,保证了代码的同步性和可见性,而 AQS 封装了线程阻塞等待挂起,解锁唤醒其他线程的逻辑。AQS 子类只需要根据状…...
Qt中信号与槽的使用
Qt中信号与槽的使用 Qt当中一个重要的东西是信号和槽,它被用于对象之间的通信。 在Qt中,例如“点击按钮”这个事件就是发送信号的对象,接收信号的是某一个窗口,响应信号的是一个处理,可以是隐藏窗口或者是关闭窗口。…...
力扣-销售员
大家好,我是空空star,本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目:607. 销售员二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其他总结前言 …...
HTML综合案例练习
一、展示简历内容 可以首先看一下我们的效果,之后再思考怎么实现 总的来说,这个练习不算难。 这里关于这个简历的代码编写我们不说太多,只注意以下几个内容即可: 注意及时查看我们的代码是否符合预期,即一段一段测 …...
MySQL运维
目录 1、日志 1、错误日志 2、二进制日志 3、查询日志 4、慢查询日志 2、主从复制 搭建 1、主库配置 2、从库配置 3、分库分表 1、简介 编辑 1、垂直拆分 2、水平拆分 3、实现技术 2、MyCat 3、MyCat使用和配置 配置 4、MyCat分片 1、垂直拆分 2、水平拆分…...
【网络原理10】构造HTTP请求、HTTPS加密
目录 一、构造HTTP请求 ①使用form表单构造HTTP请求: form表单是如何提交的 form提交的缺点 ②基于ajax构造http请求 如何使用Jquery框架 二、HTTPS 运营商劫持 HTTP的加密版本:HTTPS ①对称加密:客户端和服务端使用同一把密钥&…...
Allegro如何锁定报表界面操作指导
Allegro如何锁定报表界面操作指导 用Allegro做PCB设计的时候,进行测量的时候,比如测量器件两个PIN中间的间距,如下图,会有一个报表显示 但是当运行下一个命令的时候,报表会被自动关闭掉。 但是有时我们需要报表界面仍被保留 下面介绍如何将报表界面进行锁定,不受下一个…...
基于STM32的微型电子琴设计
基于STM32的微型电子琴设计报告中的图片和文字太多了,全部一个一个把搬过来太麻烦了,需要完整文本和代码自行q我963160156 第一章 总体设计1.1 系统功能1.2 主要技术性能指标第二章硬件设计2.1 整体硬件图2.2 按键模块2.3 扬声器模块2.4 显示模块2.5 主控模块第三章…...
Shell输入输出重定向
一、文件描述符 文件描述符是一个非负整数。它是一个索引值,指向进程打开的文件。 Linux 程序在执行任何形式的 I/O 操作时,都是在读取或者写入一个文件描述符。 每个文件描述符会与一个打开的文件相对应 不同的文件描述符也可能指向同一个文件 在L…...
华为OD机试-运维日志排序
文章目录题目描述输入描述输出描述:示例Java 代码实现题目描述 运维工程师采集到某产品线网运行一天产生的日志n条,现需根据日志时间先后顺序对日志进行排序,日志时间格式为H:M:S.N。 H表示小时(0~23) M表示分钟(0~59) S表示秒(0~59) N表…...
1Kotlin基础知识
1 变量 1.1 用法 Kotlin中的变量定义有2个关键字,val和var val用来定义不可变变量,第一次赋值后就不能再被修改了, var定义可变变量, 随便修改。一个好的编程习惯是, 能用val的就不要用var, 原因是安全&a…...
Redis Lua脚本
文章目录一.引言二.eval简介三.lua数据类型和redis数据类型之间转换四.脚本的原子性五.错误处理六.纯函数脚本七.选择内部脚本一.引言 eval和evalsha命令使用内置的lua解释器,可以对lua脚本进行求值。 二.eval简介 第一个参数是一段脚本程序第二个参数是参数的个…...
web自动化测试-执行 JavaScript 脚本
JavaScript 是一种脚本语言,有的场景需要使用 js 脚本注入辅助我们完成 Selenium 无法做到的事情。 当 webdriver 遇到无法完成的操作时,可以使用 JavaScript 来完成,webdriver 提供了 execute_script() 方法来调用 js 代码。 执行 js 有两种…...
libevent笔记——简单介绍
背景 libevent libevent – an event notification library 官方定义:libevent是一个事件通知的库。更详细的介绍参考官方的就够了,这里我摘抄一下,并做一些注释 The libevent API provides a mechanism to execute a callback function whe…...
C++学习笔记-多态
多态的概念 多态的概念:通俗来说,就是多种形态, 具体点就是去完成某个行为,当不同的对象去完成时会 产生出不同的状态 。 举个例子:比如 买票这个行为 ,当 普通人 买票时,是全价买票;…...
5632: 三角形
描述平面坐标系下,给定不共线的三个点组成一个三角形,问三角形最短的边长和最长的边长各为多少?输入输入包含3行,每行两个整数,表示一个点的坐标x和y。输出输出包括2个小数,分别为最短的边长和最长的边长。…...
Java基础--IO操作
一、IO原理及分类 一、IO原理 1、I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输,如读写文件,网络通信等。 2、java程序中对于数据的输入/输出操作一般都是以流的方式进行 3、java.io包下提供各…...
C++多线程
目录一、C线程库1. 认识thread类2. 线程函数的参数3. this_thread二、原子操作三、C互斥锁1. mutex2. lock_guard3. unique_lock四、C条件变量1. condition_variable2. 实现两个线程交替打印奇偶数一、C线程库 1. 认识thread类 在C11之前没有多线程的概念,涉及到的…...
【Arduino使用nRF24L01 】
【Arduino使用nRF24L01 】 1. 概述2. nRF24L01 收发器模块2.1工作原理2.2 NRF24L01模块变体2.3 nRF24L01 模块引脚排列3. 如何将 nRF24L01 连接到 Arduino3.1 原理接线图3.2 Arduino 和 nRF24L01 代码3.3 代码说明4. 故障排除5. 两个NRF24L01和Arduino进行双向无线通信5.1 nRF2…...
Appium自动化测试框架是一种较为优雅的使用方式
以操作小米商城下单为例流程是 启动小米商城app, 点击分类,点击小米手机, 点击小米10 至尊版,点击加入购物车,点击确定....原脚本Copyfrom time import sleep from appium import webdriver from selenium.common.exceptions impo…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...
