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

【JUC】并发编程 AQS,ReentryLock,CyclicBarrier,CountDownLatch 原理总结

AQS

AQS是什么?重写AQS就能实现锁的效果?

AQS是一个抽象类,是一个并发包的基础组件,用来实现各种锁,同步组件的工具(通过volatile + cas进行实现)。它包含了共享成员变量state、等待队列、条件队列、加锁线程 并发中的核心组件。

共享成员变量state,不同实现中有不同含义。

等待队列,基于Node内部类,实现了一个双向链表。

条件队列,基于Node内部类,实现了一个单项链表,相当于Synchronized的wait和notify的一个等待唤醒机制的条件队列。

AQS自己继承了 AbstractOwnableSynchronizer,owner就是锁的持有者,对于线程信息的封装。

AQS还为我们自己实现锁和同步器采用模板方法模式,提供了一些模板方法。我们只需要根据自己的逻辑实现方法的重写,就可以实现各种不同的互斥/同步等效果。

例如:ReentrantLock 可重入锁的实现,阻塞 加锁 解锁 等操作都是基于 ReentrantLock 内部的AQS组件实现的,本质上ReentrantLock只是提供了一系列相关的API。(Semaphore,CountDownLatch,CyclicBarrier,Renentrantreadwritelock,StampedLock)

AQS有两种模式:独占模式(ReentrantLock CycleBarrier)和 共享模式(Semaphore CountDownLatch)

独占和共享的最大区别就是State的定义不同,独占模式下State只有0和1,共享资源/临界区代码 只能由一个线程来执行,但是共享模式下的State可以为多个,只要是符合条件的当前线程都可以来使用。

补充: AQS的阻塞队列和条件队列的实现,都是通过Node节点,不过是通过Node节点的不同属性,且一个是双向 一个是单向

在这里插入图片描述

阻塞队列双向的条件队列单向?

  • 阻塞队列中被park( ) 的线程是需要由前继节点老unpark( ) 唤醒的。
    • 当node加入到阻塞队列尾部,需要找到前一个节点,把它的waitStatus设置成 -1(表示它有责任唤醒后一个节点)
  • 条件队列是由别的线程来signal( ) 唤醒的,且唤醒后会去阻塞队列中。
    • 条件队列是FIFO,尾进头出的,不需要双向。

ReentryLock

在这里插入图片描述

lock,unlock

lock

  1. 加锁成功,将state改为1,设置owner为当前线程
  2. 加锁失败
    1. 创建该线程对应的Node节点,并加入等待队列,此时waitStatus为0(默认值)
    2. 会将加入队列的该线程调用Lock。unpark( ) 来阻塞,然后设置该节点的前驱节点的waitStatus为-1(用于后续unpark( ) 它)

unlock

  1. 加锁成功的线程要解锁后会unlock( ) 掉阻塞队列中第一个节点的线程,等待队列中出来的线程获取锁成功

    1. setOwner为自己
    2. 设置state为1
    3. 更新等待队列
  2. 当unlock后,如果被unpark( ) 的线程获取锁失败,重新回到等待队列中,并park( ) 掉

锁重入

lock

  1. 第一次会正常加上锁,setOwner是自己,然后修改state为1。
  2. 第二次同一个线程又来加锁了,会检查到当前线程=owner线程,说明发生了锁重入现象。
  3. 然后会对state++,做一个累加操作,作为锁重入的计数。

unlock

  1. state–;
  2. 只是一直对state–,并没有真正的释放锁,当state==0时,说明才真的该释放锁。
  3. state==0 时再执行unlock方法流程。

可打断

  • ReentrantLock分为不可打断模式 和 可打断模式: lock.lock() 不可被打断 lock.lockInterruptibly(); 可被打断
  • 使用时在API使用的不同选择的就是不同模式的加锁解锁方式

区别:

  • 不可打断模式没有真的打断,只是设置打断标记为true。还是继续停留在等待队列中等待。当获取到锁之后才检查是否被打断,再进行打断。
  • 可打断模式打断了,通过抛出异常的方式保证当前线程被打断。

公平,非公平

非公平锁(默认)和公平锁的主要区别在于 tryAcquire( ) 的实现。【尝试获取锁的方法】

当 state == 0 后的操作不同!

  • 非公平锁一上来不会看等待队列中是否有阻塞等待的线程,而是直接去cas操作去判断state来竞争锁
  • 公平锁一上来不会直接cas操作获取修改state,而是先判断等待队列中是否有优先级比我高的队列,实现了公平

相对来说,非公平锁会更好的性能,因为它的吞吐量比较大。

当然,非公平锁让获取锁的时间变得更加不确定,可能会导致在阻塞队列中的线程长期处于饥饿状态。

在这里插入图片描述

公平构造为 FairSync()

条件变量

每个条件变量其实对应着一个等待队列,其实现类是ConditionObject。

ConditionObject中维护了以Node为节点的双向链表所构成的队列。但是只使用了单向!

Await( )

  1. 首先获取到锁,然后条件不满足时调用await( ) 。
    • 此时创建一个新的Node状态为 -2,并联这个不满足条件的线程,加入条件队列的尾部。
  2. 进入AQS的fullRelease,释放掉同步器上的锁。
    1. 设置owner为null
    2. setState = 0
    3. unpark( ) 等待队列中的线程
  3. 去条件变量中等待的线程也会被park( ) 进入阻塞状态

Signal( )

(有一个节点的转移,会条件队列中获取队头元素转移到等待队列队尾,并重置waitStatus=0)

只有owner中的线程才有资格唤醒条件变量中的所有者!

  1. 取得在条件变量中(队首)的第一个Node
  2. 会将满足条件的该线程转移到等待队列中等待下次重新获取锁。
  3. 并将当前线程状态从-2改为0。因为等待队列中每次增加的元素都默认是0。

在这里插入图片描述

锁超时

public boolean tryLock():尝试获取锁,获取到返回 true,获取不到直接放弃,不进入阻塞队列

public boolean tryLock(long timeout, TimeUnit unit):在给定时间内获取锁,获取不到就退出

实现原理

  • 成员变量:指定超时限制的阈值,小于该值的线程不会被挂起,会自旋

    static final long spinForTimeoutThreshold = 1000L;
    

    超时时间设置的小于该值,就会被禁止挂起,因为阻塞在唤醒的成本太高,不如选择自旋空转

  • tryLock()

    sync.nonfairTryAcquire(1);// 只尝试一次
    
  • tryLock(long timeout, TimeUnit unit)

    //先尝试一次nonfairTryAcquire()后doAcquireNanos(arg, nanosTimeout);
    // 获取最后期限的时间戳
    // 计算还需等待的时间
    // 时间已到     return false;
    // 如果 nanosTimeout 大于该值,才有阻塞的意义,否则直接自旋会好点
    

ReentrantLock 对比 Synchronized

ReentrantLock 相对于 synchronized 具备如下特点:

  1. 锁的实现:synchronized 是 JVM 实现的,而 ReentrantLock 是 JDK 实现的
  2. 性能:新版本 Java 对 synchronized 进行了很多优化,synchronized 与 ReentrantLock 大致相同
  3. 使用:ReentrantLock 需要手动解锁,synchronized 执行完代码块自动解锁
  4. 可中断:ReentrantLock 可中断,而 synchronized 不行
  5. 公平锁:公平锁是指多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁
    • ReentrantLock 可以设置公平锁,synchronized 中的锁是非公平的
    • 不公平锁的含义是阻塞队列内公平,队列外非公平
  6. 锁超时:尝试获取锁,超时获取不到直接放弃,不进入阻塞队列
    • ReentrantLock 可以设置超时时间,synchronized 会一直等待
  7. 锁绑定多个条件:一个 ReentrantLock 可以同时绑定多个 Condition 对象,更细粒度的唤醒线程
  8. 两者都是可重入锁

C​y​cli​c​B​arr​i​er​ 对比 Count​Do​wn​La​t​ch​​

使用上的区别就是 CountDownLatch 的计数只能使用一次,CyclicBarrier在计数变为0之后,会重置计数!

  1. 等待主体不同。调用await( ) 方法的对象不同。
    1. CountDownLatch是主线程调用await( ) 来等待其他线程将state减为0再来执行。阻塞的是主线程。
    2. CyclicBarrier是工作线程调用await( ) ,await( ) 方法会对自身维护的计数器 -1 操作。阻塞的是工作线程。
      • 多组线程等待共同到达一个栅栏点,通过 signalAll( ) 一起出来,并且把 count 重新置为 parties。
  2. CountDownLatch是通过AQS的State信号量来实现的,而CyclicBarrier是直接借助ReentrantLock加上Condition 等待唤醒的功能 进而实现的。

在这里插入图片描述

相关文章:

【JUC】并发编程 AQS,ReentryLock,CyclicBarrier,CountDownLatch 原理总结

AQS AQS是什么?重写AQS就能实现锁的效果? AQS是一个抽象类,是一个并发包的基础组件,用来实现各种锁,同步组件的工具(通过volatile cas进行实现)。它包含了共享成员变量state、等待队列、条件…...

移动端底层事件(如左滑返回事件)在同一个路由下不同页面需要不同的处理要怎样才能做到统一处理?

目录 一、问题 二、解决方法 三、总结 tiips:如嫌繁琐,直接移步总结即可! 一、问题 1.测试提了个bug:进入了一个模块A里面的子页面 a1,左滑后按照用户预期应该是返回到模块A,结果回到了app首页。 二、解决方法 1.一开始:啊,…...

hive中开窗函数row_number的使用

row_number()函数介绍 row_number()开窗函数的一种,和over()函数结合一起使用,可以实现对数据的分组和排序。 使用示例 现在有一张表,数据如下 ----------------------- | Year | Region | Sales | ----------------------- | 2022 | E…...

华为数据之道第三部分导读

目录 导读 第三部分 第7章 打造“数字孪生”的数据全量感知能力 “全量、无接触”的数据感知能力框架 数据感知能力的需求起源:数字孪生 数据感知能力架构 基于物理世界的“硬感知”能力 “硬感知”能力的分类 “硬感知”能力在华为的实践 基于数字世界的…...

【Qt】常用控件(一)

文章目录 一、核心属性1、enabled代码示例: 通过按钮2 切换按钮1 的禁用状态 2、geometry代码示例: 控制按钮的位置代码示例:window frame 的影响代码示例: 感受 geometry 和 frameGeometry 的区别 3、windowTitle4、windowIcon代码示例: 通过 qrc 管理图片作为图标…...

Python基础之流程控制语句

在Python中流程控制语句包括条件控制语句、循环语句、以及控制流程循环语句等,下面我们就来详细介绍一下这些语句的使用。 条件语句 首先我们来看条件语句,条件语句是需要根据不同的判断条件来执行不同的代码操作,如下所示。 if 条件1:执行语句块1 elif 条件2:执行语句块…...

2024蓝桥杯网络安全部分赛题wp

爬虫协议 题目给了提示访问robots.txt 会出三个目录 访问最后一个 点进去就flag{22560c15-577c-4c8b-9944-815473758bad} packet 下载附件,这个是流量包 放wireshark流量分析 搜http协议 发现有cat flag命令,直接看他返回的流量 最后base64解码即可…...

Android版本依赖Version catalog

曾经我们使用config.gradle文件进行版本依赖配置,然后在project的build.gradle.kts中使用如下方式引入: apply(from "./config.gradle") 缺点:在project的module中引用无任何提示,无法跳转到指定引用 一、创建versio…...

Redis---------实现商品秒杀业务,包括唯一ID,超卖问题,分布式锁

订单ID必须是唯一 唯一ID构成: 代码生成唯一ID: import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.tim…...

C++之QT文本处理QDir、QFileDialog、QStringList、QFile

一、相应的头文件 #include <QFileDialog> #include <QDir> #include <QStringList> 二、简介 1.QFileDialog 实际效果如下&#xff1a;比如需要选择打开的文件夹或者文件名&#xff0c;通过调用资源管理器的方式进行可视化操作。 代码示例为&#xff1a…...

24.5.8数据结构|单向循环链表

一、理解原理&#xff1a; 初始状态&#xff1a; 1、对比前两种的不同之处 1&#xff09;保存到栈空间&#xff08;局部变量&#xff09;。静态初始化。 2&#xff09; 二、代码实现 1、initLinkLoop函数 疑问&#xff1a; 1、地址怎么处理&#xff1f; 注意&#xff1…...

2024年,抖音小店开通需要多少钱?一篇详解!

大家好&#xff0c;我是电商糖果 2024年了&#xff0c;想在抖音开店卖货的朋友越来越多。 主要原因还是看到&#xff0c;这几年在抖音上赚到钱的人越来越多。 于是大家在今年比较关心的问题&#xff0c;就是抖音小店开通需要多少钱&#xff1f; 糖果做抖音小店四年了&#…...

2023年全国职业院校技能大赛(高职组)“云计算应用”赛项赛卷1(私有云)

#需要资源&#xff08;软件包及镜像&#xff09;或有问题的&#xff0c;可私聊博主&#xff01;&#xff01;&#xff01; #需要资源&#xff08;软件包及镜像&#xff09;或有问题的&#xff0c;可私聊博主&#xff01;&#xff01;&#xff01; #需要资源&#xff08;软件包…...

Python数据可视化------地图

基础地图使用 # 地图基本演示 # 导包 from pyecharts.charts import Map from pyecharts.options import TitleOpts, VisualMapOpts# 准备地图对象 cmap Map() # 准备数据&#xff08;列表&#xff09; data [("北京市", 99), ("上海市", 199), ("…...

Rust中的并发性:Sync 和 Send Traits

在并发的世界中&#xff0c;最常见的并发安全问题就是数据竞争&#xff0c;也就是两个线程同时对一个变量进行读写操作。但当你在 Safe Rust 中写出有数据竞争的代码时&#xff0c;编译器会直接拒绝编译。那么它是靠什么魔法做到的呢&#xff1f; 这就不得不谈 Send 和 Sync 这…...

|Python新手小白中级教程|第二十七章:面向对象编程(示例操作)(3)使用turtle库与类结合

文章目录 前言一、项目&#xff1a;使用类Circle画出圆形&#xff08;不调用turtle库&#xff09;1.基础指令class2.使用turtle画出大圆与小圆3.使用其他功能画一只眼睛 二、使用turtle库画正方形总结 前言 hello&#xff0c;我是BoBo仔&#xff0c;welcome来看我的文章 这节课…...

Android OpenMAX(五)高通OMX Core实现

上一节了解了OMX Core提供的内容,这一节我们看看高通OMX Core是如何实现的。本节代码参考自: omx_core_cmp.cpp registry_table_android.c qc_omx_core.h 1、OMX_Init/OMX_Deinit OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Init() {DEBUG_PRINT(...

XXE漏洞

一、概述 1、XXE&#xff1a;XML外部实体注入攻击 2、XML&#xff1a;可扩展标记语言。 (1)没有固定标签&#xff0c;所有标签都可以自定义&#xff0c;但有限制规则。 (2)用于数据对的传输与存储&#xff0c;常被用于充当配置文件 推荐教程&#xff1a;XML 教程 (3)后缀…...

[华为OD]C卷 BFS 亲子游戏 200

题目&#xff1a; 宝宝和妈妈参加亲子游戏&#xff0c;在一个二维矩阵&#xff08;N*N&#xff09;的格子地图上&#xff0c;宝宝和妈妈抽签决定各自 的位置&#xff0c;地图上每个格子有不同的Q糖果数量&#xff0c;部分格子有障碍物。 游戏规则Q是妈妈必须在最短的时间&a…...

大模型微调实战之强化学习 贝尔曼方程及价值函数(五)

大模型微调实战之强化学习 贝尔曼方程及价值函数&#xff08;五&#xff09; 现在&#xff0c; 看一下状态-动作值函数的示意图&#xff1a; 这个图表示假设首先采取一些行动(a)。因此&#xff0c;由于动作&#xff08;a&#xff09;&#xff0c;代理可能会被环境转换到这些状…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

恶补电源:1.电桥

一、元器件的选择 搜索并选择电桥&#xff0c;再multisim中选择FWB&#xff0c;就有各种型号的电桥: 电桥是用来干嘛的呢&#xff1f; 它是一个由四个二极管搭成的“桥梁”形状的电路&#xff0c;用来把交流电&#xff08;AC&#xff09;变成直流电&#xff08;DC&#xff09;。…...

《信号与系统》第 6 章 信号与系统的时域和频域特性

目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...

鸿蒙HarmonyOS 5军旗小游戏实现指南

1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;采用DevEco Studio实现&#xff0c;包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...