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

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 的加锁过程,可以分为三个阶段
    1. 尝试加锁:tryAcquire()
      在这里插入图片描述
    • 当出现 锁已经被其他线程获取 / 锁没有被其他线程获取,但当前线程需要排队 / cas 失败 这三种情况时,会导致获取锁失败
    • 锁为自由状态,并不能说明可以立刻执行 cas 获取锁,因为可能在当前线程获取锁之前,已经有其他线程在排队了,必须 遵循先来后到的原则获取锁。还要调用 hasQueuedPredecessors()方法,查看自己是否需要排队
    1. 加锁失败,线程进入队列:acquireQueued()
      在这里插入图片描述

    2. 线程入队列后,进入阻塞状态: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++学习笔记-多态

多态的概念 多态的概念:通俗来说,就是多种形态, 具体点就是去完成某个行为,当不同的对象去完成时会 产生出不同的状态 。 举个例子:比如 买票这个行为 ,当 普通人 买票时,是全价买票&#xff1b…...

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…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

云计算——弹性云计算器(ECS)

弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

ESP32读取DHT11温湿度数据

芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...