ReentrantLock 实现公平锁和非公平锁的原理!

在这里插入图片描述

🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!

🌟了解 ThreadLocal请看: ThreadLocal有趣讲解,小白也能听懂!

其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏(已完结)】…等

如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning

想象一下,有一个很受欢迎的公共厕所 🚽,同一时间只能一个人进去。

ReentrantLock 就好比是这个厕所的门锁管理员。他负责管理谁能进去。

深入了解 ReentrantLock 请看:ReentrantLock:可定制的“VIP 包间”

核心原理:AQS

ReentrantLock 的底层依赖一个叫做 AQS 的框架。你可以把 AQS 理解为一个通用的排队和状态管理系统

  1. 状态 (State): AQS 内部有一个 state 变量(是个整数)。在 ReentrantLock 里:
    • state = 0: 表示厕所现在没人,门是空闲的 ✅。
    • state > 0: 表示厕所有人,门被占用了 🔒。这个数字还表示同一个人重复进入(重入)了多少次。比如一个人进去后,又在里面锁了一层门,state 就变成 2。
  2. 等待队列 (Queue): AQS 维护了一个等待队列。这个队列像银行排队的队伍一样,是先进先出 (FIFO) 的 🚶‍♂️🚶‍♀️🚶‍♂️。想上厕所但发现里面有人的人(线程),就会被安排到这个队列里排队等着。

非公平锁 (Nonfair Lock) - 默认模式

  • 解释: 就像一个秩序不太好的厕所。
    • 当你(线程)想上厕所时,你首先会冲到门口 🏃💨,猛地推一下门,看看是不是正好没人(尝试用 CAS 原子操作直接把 state 从 0 改成 1)。
    • 如果正好没人,恭喜你 🎉,你直接就进去了!哪怕旁边已经有人在排队等了很久,你也可能因为动作快而“插队”成功。
    • 如果里面有人(推门失败,state 不是 0),或者你尝试抢锁的那一下正好别人也抢成功了,那你没办法 😟,只能乖乖去队伍(AQS 队列)后面排着
    • 当里面的人出来(释放锁)时,管理员(AQS)会唤醒 ⏰ 队伍最前面的人。但是,与此同时,如果又有一个新人跑过来直接推门 🏃💨,并且正好成功了,那这个刚被唤醒、正准备进去的人可能又得等一下。
  • 底层实现关键点:
    • 调用 lock() 时,先尝试直接获取锁(CAS 修改 state)。
    • 获取失败,才把自己加入 AQS 等待队列。
    • 释放锁时,唤醒队头节点,但新来的线程仍有机会抢先获取锁
  • 优点: 可能性能更好,吞吐量更高 🚀。因为减少了线程挂起和唤醒的次数(如果运气好直接抢到锁,就不用排队和被唤醒了)。
  • 缺点: 可能导致饥饿 😩。排在前面的线程可能一直等不到锁,因为总有新来的线程“插队”成功。

公平锁 (Fair Lock)

  • 解释: 就像一个非常有秩序的厕所 👍。
    • 当你(线程)想上厕所时,你首先会看一眼 👀 队伍前面有没有人排队 (hasQueuedPredecessors() 检查)。
    • 如果队伍里有人,对不起 🙅‍♂️,你不能直接去推门,必须老老实实去队伍(AQS 队列)后面排着 🚶‍♂️🚶‍♀️。
    • 只有当队伍是空的,你才可以去尝试推门(尝试 CAS 修改 state)。
    • 当里面的人出来(释放锁)时,管理员(AQS)只会唤醒队伍最前面的那个人,并且只有这个人能进去。新来的人?对不起,看队伍里有人,请自觉排队。
  • 底层实现关键点:
    • 调用 lock() 时,先检查 AQS 队列中是否有等待者
    • 如果有等待者,则不尝试获取锁,直接加入队列尾部。
    • 只有当队列为空时,才尝试获取锁。
    • 释放锁时,严格唤醒并让队头节点获取锁
  • 优点: 公平 ⚖️,保证了先来后到,不会有线程饿死。
  • 缺点: 性能相对较低,吞吐量可能不如非公平锁 📉。因为即使锁是空闲的,只要队列里有人,新来的线程也得去排队,导致更多的线程挂起和唤醒,增加了上下文切换的开销。

总结一下 ↔️:

ReentrantLock 通过内部的 Sync 类(它继承了 AQS)来实现锁逻辑 🛠️。Sync 有两个子类:NonfairSyncFairSync

  • 核心区别在于尝试获取锁 (tryAcquire 方法) 时的行为:
    • NonfairSync: 直接尝试 CAS 修改 state,失败再入队。
    • FairSync: 先检查队列是否为空或者自己是不是队头,满足条件才尝试 CAS 修改 state,否则直接入队。

🤔 默认情况下,new ReentrantLock() 创建的是非公平锁,因为它通常有更好的性能。如果你需要保证公平性,可以使用 new ReentrantLock(true) 来创建公平锁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/76312.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NLP高频面试题(四十一)——什么是 IA3 微调?

随着大型语言模型的广泛应用,如何高效地将这些模型适配到特定任务中,成为了研究和工程实践中的重要课题。IA3(Infused Adapter by Adding and Adjusting)微调技术,作为参数高效微调的一种新颖方法,提供了在保持模型性能的同时,显著减少可训练参数数量的解决方案。 IA3 …

swift菜鸟教程14(闭包)

一个朴实无华的目录 今日学习内容:1.Swift 闭包1.1闭包定义1.2闭包实例1.3闭包表达式1.3.1sorted 方法:据您提供的用于排序的闭包函数将已知类型数组中的值进行排序。1.3.2参数名称缩写:直接通过$0,$1,$2来顺序调用闭包的参数。1.3.3运算符函…

蓝桥杯-蓝桥幼儿园(Java-并查集)

并查集的核心思想 并查集主要由两个操作构成: Find:查找某个元素所在集合的根节点。并查集的特点是,每个元素都指向它自己的父节点,根节点的父节点指向它自己。查找过程中可以通过路径压缩来加速后续的查找操作,即将路…

ruby内置全局变量

以下是 Ruby 中常见的 内置全局变量 及其用途的详细说明。这些变量以 $ 开头,由 Ruby 解释器自动管理,用于访问系统状态、异常、输入输出等核心信息。 一、异常处理相关 全局变量说明示例$!当前作用域最后抛出的异常对象(等同于 rescue >…

tcp转串口

windows 在 Windows 系统上,可以使用以下成熟的串口转 TCP 工具: HW VSP3 (HW Virtual Serial Port) 提供串口到 TCP/IP 的映射功能。支持虚拟串口和网络通信。下载地址:HW Group com0com com2tcp 开源工具,支持虚拟串口和 TCP…

HTML视频和音频

<video>元素 <video>元素用于在HTML文档中嵌入视频内容。 <video controls><source src"movie.mp4" type"video/mp4"><source src"movie.ogg" type"video/ogg">您的浏览器不支持 HTML5 video 标签。 …

DeepSeek:重构办公效率的AI新范式

目录 一、效率跃迁的三重引擎 二、效率提升的量级突破 三、智能办公的范式转移 四、未来办公的效率奇点 当企业主面对堆积如山的文件审批、跨时区协作的沟通损耗、重复机械的数据整理时&#xff0c;是否想过这些场景正在吞噬团队的生产力&#xff1f;据麦肯锡研究显示&…

redis 延迟双删

Redis延迟双删是一种用于解决缓存与数据库数据一致性问题的策略&#xff0c;通常在高并发场景下使用。以下是其核心内容&#xff1a; 1. 问题背景 当更新数据库时&#xff0c;如果未及时删除或更新缓存&#xff0c;可能导致后续读请求仍从缓存中读取旧数据&#xff0c;造成数…

Python设计模式:策略模式

1. 什么是策略模式 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一系列算法&#xff0c;将每个算法封装起来&#xff0c;并使它们可以互换。策略模式使得算法的变化独立于使用算法的客户。换句话说&#xff0c;策略模式允许在运…

SpringBoot集成Ollama本地模型

SpringBoot集成Ollama本地模型 目录 项目准备创建Ollama服务客户端创建控制器配置应用属性创建前端界面添加静态资源支持完整项目结构启动应用高级功能扩展部署注意事项性能优化 1. 项目准备 创建一个SpringBoot项目&#xff0c;可以使用Spring Initializr或IDE创建添加必要…

ResNet改进(19):基于PyTorch的ResNet改进方案详解:Mish激活+SPP模块+MixUp数据增强

1. 前言 ResNet作为深度学习领域里程碑式的网络架构,在图像分类等计算机视觉任务中表现出色。然而,随着研究的深入和技术的发展,原始的ResNet架构仍有改进空间。本文将详细介绍一种基于PyTorch的ResNet改进方案,该方案融合了Mish激活函数、SPP模块和MixUp数据增强等先进技…

leetcode68.左右文本对齐

思路源自 leetcode-字符串篇 68题 文本左右对齐 难度高的模拟类型题目&#xff0c;关键点在于事先知道有多少单词要放在本行并且还要知道本行是不是最后一行&#xff08;最后一行需要全部单空格右对齐&#xff0c;不是最后一行就空格均摊&#xff09;&#xff0c;非最后一行的空…

深入理解 Spring 的 MethodParameter 类

MethodParameter 是 Spring 框架中一个非常重要的类&#xff0c;它封装了方法参数&#xff08;或返回类型&#xff09;的元数据信息。这个类在 Spring MVC、AOP、数据绑定等多个模块中都有广泛应用。 核心功能 MethodParameter 主要提供以下功能&#xff1a; 获取参数类型信息…

Qt 5.14.2入门(一)写个Hello Qt!程序

目录 参考链接&#xff1a;一、新建项目二、直接运行三、修改代码增加窗口内容1、Qt 显示一个 QLabel 标签控件窗口2、添加按键 参考链接&#xff1a; Qt5教程&#xff08;一&#xff09;&#xff1a;Hello World 程序 Qt 编程指南 一、新建项目 1、新建一个项目&#xff08…

Spring Boot 3.x 集成 MongoDB 的 默认配置项及默认值,以及 常用需要修改的配置项 的详细说明

以下是 Spring Boot 3.x 集成 MongoDB 的 默认配置项及默认值&#xff0c;以及 常用需要修改的配置项 的详细说明&#xff1a; 一、默认配置项及默认值 Spring Boot 对 MongoDB 的默认配置基于 spring.data.mongodb 前缀&#xff0c;以下是核心配置项&#xff1a; 配置项默认…

【QT】 进程

目录 QT 多进程复习 Linux-C 多进程QProcess 进程类常用方法简单示例信号与槽应用场景 跨平台注意事项技巧&#xff1a;使用宏控制平台命令 QProcess 在嵌入式系统中的使用示例&#xff1a;调用 ALSA 播放音频示例&#xff1a;调用 arecord 录音示例&#xff1a;QProcess Shel…

原子操作(cpp atomic)

目录 一.原子操作 1.原子操作的概念 2.原子变量 二.原子性 1.中间状态描述 2.单处理器单核 3.多处理器或多核的情况下 4.cache&#xff08;高速缓冲器的作用&#xff09; 5.在cpu cache基础上,cpu如何读写数据&#xff1f;&#xff1f;&#xff1f; 6.为什么会有缓存…

Unet网络的Pytorch实现和matlab实现

文章目录 一、Unet网络简介1.1 输入图像1.2 编码器部分&#xff08;Contracting Path&#xff09;1.3 解码器部分&#xff08;Expanding Path&#xff09;1.4 最后一层&#xff08;输出&#xff09;1.5 跳跃连接&#xff08;Skip Connections&#xff09; 二、Unet网络的Pytorc…

记录一次JVM调优过程1

如何通过jmap 诊断&#xff0c;服务运行一段时间后内存使用量飙升的问题 通过 jmap 诊断服务运行一段时间后内存使用量飙升的问题&#xff0c;需结合堆转储分析、对象分布统计及工具链配合。以下是具体操作步骤和关键方法&#xff1a; 一、实时监控与初步分析 获取进程 PID 使…

接口自动化学习五:mock工具使用

Moco简介&#xff1a; Mock是一个简单搭建模拟服务器的框架&#xff0c;可以用来模拟http、https、socket等协议。 原理&#xff1a; Mock会根据一些配置&#xff0c;启动一个真正的HTTP服务&#xff08;会监听本地的某个端口&#xff09;,当发起的请求满足某个条件时&#xf…