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

锁策略总结

锁策略

悲观锁和乐观锁

乐观锁和悲观锁不是具体类型的锁而是指两种不同的对待加锁的态度,这两个锁面对锁冲突的态度是相反的。

  • 乐观锁:认为不存在很多的并发操作,因此不需要加锁。
  • 悲观锁:认为存在很多并发操作,因此需要加锁。

重量级锁和轻量级锁

重量级锁和轻量级锁是通过结果去看待加锁解锁的过程开销。做的工作多消耗资源多,做的工作少消耗资源少。因此我们会认为乐观锁是轻量级锁,悲观锁是重量级锁。

  • 重量级锁:是进入内核态的加锁逻辑,资源开销较大。
  • 轻量级锁:是纯用户态的加锁逻辑,资源开销较小。  

自旋锁和挂起等待锁

  • 自旋锁:是一种轻量级锁,自旋锁类是一直反复查看当前锁是否就绪,CPU不停空转会消耗大量地CPU。
  • 挂起等待锁:是一种重量级锁,该锁不会像自旋锁一样一直查看锁状态而是先去做别的事情,过一会再来看当前锁是否就绪。

互斥锁和读写锁

  • 互斥锁:当两个线程竞争同一把锁时会产生锁冲突进而阻塞等待。
  • 读写锁:根据代码实际的逻辑进行加锁,有读锁和写锁两种锁。读锁和读锁之间不会产生锁竞争;读锁和写锁之间会产生锁竞争;写锁和写锁之间,会产生锁竞争。如果代码中读的场景多写的场景少时,读写锁相比于互斥锁优化了效率、减少了不必要的锁竞争。

可重入锁和不可重入锁 

  • 不可重入锁:是指同一个线程对同一把锁连续加锁两次,产生了死锁。
  • 可重入锁:是指同一个线程在外层方法获取锁,进入内层方法会自动获取锁。

注ReentrantLock和Synchronized都是可重入锁。

公平锁和非公平锁

  • 公平是指遵循先来后到的原则的,因此遵守先来后到就是公平锁,不遵守先来后到的就是非公平锁。
  • 例:t1,t2,t3三个线程竞争同一把锁,谁先来的谁就拿到锁的情况叫公平锁。如果三个线程随机一个拿到锁,后来的线程可能会先拿到锁的情况叫非公平锁。
  • 公平锁:指多个线程按照申请锁的顺序来获取锁。
  • 非公平锁:指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。

 操作系统默认的锁的调度是非公平的。系统对于线程的调度是随机的,自带的synchronized这个锁是非公平的。想要实现公平锁需要在synchronized的基础上,加个队列来记录这些加锁线程的顺序。

cas 和 synchronized 优化过程

CAS全称: compare and swap. 根据字面意思理解为"比较并交换"

一个CAS涉及到以下操作:

假设内存中的原数据是V,旧的预期值是A,需要修改的新值是B

1).先比较A和V是否相等(比较)

2).如果比较相等,就将B写入V(交换)

3).返回操作是否成功

 

在上述交换过程中,大多数情况下并不关心B后续的情况,更关心的是V这个变量的情况

这里说是交换,其实可以近似理解成:赋值

此处最特别的地方是:上述这个CAS过程并非是通过一段代码实现的,而是通过一条CPU指令完成的,这说明CAS操作是原子的!!!!!

CAS可以理解成是CPU提供的一个特殊指令,通过这个指令可以一定程度上处理线程安全问题.

CAS的伪代码:

boolean CAS(value, oldValue, swapValue) {if (value == oldValue) {value = swapValue;return true;}return false;
}

CAS的应用场景

CAS的应用场景主要有两个:

1).实现原子类

     java标准库提供了java.util.concurrent.atomic包,里面的类都是基于CAS的方式实现的,其中最典型的就是AtomicInteger类,其中的getAndIncrement相当于i++操作

    通过下面一个练习来理解原子类:

    两个线程增加同一个变量

public class Exercise {public static void main(String[] args) throws InterruptedException {AtomicInteger integer = new AtomicInteger(0);Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {integer.getAndIncrement();// 相当于i++操作}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {integer.getAndIncrement();// 相当于i++操作}});t1.start();t2.start();// 为了让主线程等待t1线程和t2线程执行完毕t1.join();t2.join();System.out.println(integer);}
}

实现自旋锁

通过下面的伪代码理解:

public class SpinLock { private Thread owner = null; public void lock(){// 通过 CAS 看当前锁是否被某个线程持有. // 如果这个锁已经被别的线程持有, 那么就自旋等待. // 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程. while(!CAS(this.owner, null, Thread.currentThread())){}}public void unlock (){this.owner = null;}
}

ABA问题

CAS运行的核心:检查value与oldValue是否一致.如果一致,就视为value中途没有被修改过,所以进行下一步交换操作是没问题的.

但是,这里的一致,可能是value没有被修改过,也有可能是value被修改过又改回来了. 

把value的值设为A的话,CAS判定value为A,此时value的值可能始终为A,也可能是value本来是A,被修改为了B,最后又还原成了A.

这就是CAS的典型问题:ABA问题

假设 张三 有 100 存款 . 张三 想从 ATM 取 50 块钱 . 取款机创建了两个线程 , 并发的来执行 -50
操作 .
我们期望一个线程执行 -50 成功 , 另一个线程 -50 失败 .
如果使用 CAS 的方式来完成这个扣款过程就可能出现问题 .
正常的过程
1) 存款 100. 线程 1 获取到当前存款值为 100, 期望更新为 50; 线程 2 获取到当前存款值为 100, 期
望更新为 50.
2) 线程 1 执行扣款成功 , 存款被改成 50. 线程 2 阻塞等待中 .
3) 轮到线程 2 执行了 , 发现当前存款为 50, 和之前读到的 100 不相同 , 执行失败 .

异常的过程
1) 存款 100. 线程 1 获取到当前存款值为 100, 期望更新为 50; 线程 2 获取到当前存款值为 100, 期
望更新为 50.
2) 线程 1 执行扣款成功 , 存款被改成 50. 线程 2 阻塞等待中 .
3) 在线程 2 执行之前 ,张三 的朋友正好给张三转账 50, 账户余额变成 100 !!
4) 轮到线程 2 执行了 , 发现当前存款为 100, 和之前读到的 100 相同 , 再次执行扣款操作
这个时候 , 扣款操作被执行了两次 !!! 

 

解决ABA问题的方法:给要修改的值,引入版本号

在 CAS 比较数据当前值和旧值的同时 , 也要比较版本号是否符合预期 .
CAS 操作在读取旧值的同时 , 也要读取版本号 .
真正修改的时候:
如果当前版本号和读到的版本号相同 , 则修改数据 , 并把版本号 + 1.
如果当前版本号高于读到的版本号 . 就操作失败 ( 认为数据已经被修改过了 ).
引入版本号后,解决刚才转账异常的情况:
假设 张三 有 100 存款 . 张三 想从 ATM 取 50 块钱 . 取款机创建了两个线程 , 并发的来执行 -50
操作 .
我们期望一个线程执行 -50 成功 , 另一个线程 -50 失败 .
为了解决 ABA 问题 , 给余额搭配一个版本号 , 初始设为 1.
1) 存款 100. 线程 1 获取到 存款值为 100, 版本号为 1, 期望更新为 50; 线程 2 获取到存款值为 100,
版本号为 1, 期望更新为 50.
2) 线程 1 执行扣款成功 , 存款被改成 50, 版本号改为 2. 线程 2 阻塞等待中 .
3) 在线程 2 执行之前 , 张三 的朋友正好给滑稽转账 50, 账户余额变成 100, 版本号变成 3.
4) 轮到线程 2 执行了 , 发现当前存款为 100, 和之前读到的 100 相同 , 但是当前版本号为 3, 之前读
到的版本号为 1, 版本小于当前版本 , 认为操作失败 .

Synchronized 

1).synchronized既是一个悲观锁,也是一个乐观锁

    synchronized默认是乐观锁,但是如果发现锁竞争激烈,就会变成悲观锁

2).synchronized既是一个轻量级锁,也是一个重量级锁

    synchronized默认是轻量级锁,但是如果发现锁竞争激烈,就会变成重量级锁

3).synchronized这里的轻量级锁,是基于自旋锁的方式实现的.

    synchronized这里的重量级锁,是基于挂起等待锁的方式实现的.

4).synchronized 不是读写锁

5).synchronized 是非公平锁

6).synchronized 是可重入锁


jvm将synchronized 锁分为:无锁 偏向锁 轻量级锁 重量级锁 状态,会根据情况,进行依次升级.

1).偏向锁

     第一个尝试加锁的线程,优先进入偏向锁状态.偏向锁不是真的"加锁",而是做个偏向锁标记,记录这个锁属于哪个线程.

    如果整个使用锁的过程中,没有出现锁竞争,在synchronized执行完之后,取消偏向锁即可

    如果整个使用锁的过程中.另一个线程也尝试加锁,那么在它加锁之前,迅速的把偏向锁状态升级为加锁状态,另一个线程只能阻塞等待了.


2).轻量级锁

     随着其它线程进入竞争,偏向锁状态被消除,进入轻量级锁状态(自适应的自旋锁)

     此处的轻量级锁就是通过CAS来实现的.

     自旋操作是一直让CPU空转,比较浪费CPU资源,因此,此处的自旋不会一直持续进行,而是达到一定的时间/重试次数,就不在自旋了,也就是所谓的"自适应".


3).重量级锁

    如果竞争进一步激烈,自旋不能快速获取到锁,就会升级为重量级锁

    此处的重量级锁就是指用到内核提供的mutex

之后还有关于Synchronized 的内容,下次放送。

相关文章:

锁策略总结

锁策略 悲观锁和乐观锁 乐观锁和悲观锁不是具体类型的锁而是指两种不同的对待加锁的态度&#xff0c;这两个锁面对锁冲突的态度是相反的。 乐观锁&#xff1a;认为不存在很多的并发操作&#xff0c;因此不需要加锁。悲观锁&#xff1a;认为存在很多并发操作&#xff0c;因此需…...

蓝桥杯备考day2

1.1 map及其函数 map 提供一对一的数据处理能力&#xff0c;由于这个特性&#xff0c;它完成有可 能在我们处理一对一数据的时候&#xff0c;在编程上提供快速通道。map 中的第一 个值称为关键字(key)&#xff0c;每个关键字只能在 map 中出现一次&#xff0c;第二个称为该 关…...

Mac电脑安装蚁剑

1&#xff1a; github 下载源码和加载器&#xff1a;https://github.com/AntSwordProjectAntSwordProject GitHubAntSwordProject has 12 repositories available. Follow their code on GitHub.https://github.com/AntSwordProject 以该图为主页面&#xff1a;antSword为源码…...

品牌百度百科词条创建多少钱?

百度百科作为国内最具权威和影响力的知识型平台&#xff0c;吸引了无数品牌和企业争相入驻。一个品牌的百度百科词条&#xff0c;不仅是对品牌形象的一种提升&#xff0c;更是增加品牌曝光度、提高品牌知名度的重要途径。品牌百度百科词条创建多少钱&#xff0c;这成为了许多企…...

Linux安装及管理程序

目录 一.Linux应用程序基础 1.应用程序与系统命令的关系 2.典型应用程序的目录结构 3.常见的Linux软件包封装类型 二.RPM 软件包管理工具 1.RPM 软件包管理器 Red-Hat Package Manger 2.RPM软件包 3.RPM命令 三.源代码编译安装 1. yum 软件包管理器&#xff1a; 配…...

Mybatis generate xml 没有被覆盖

添加插件即可 <plugin type"org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>...

MercadoLibre(美客多)入仓预约系统操作流程-自动化约号(开篇)

目录 一、添加货件信息 二、输入货件信息 三、选择发货 四、填写交货日期 五、注意事项 MercadoLibre&#xff08;美客多&#xff09;于2021年10月18号上线了新预约入仓系统&#xff0c;在MercadoLibre美客多平台上&#xff0c;新入仓预约系统是一项非常重要的功能&#x…...

Unity TextMeshProUGUI 获取文本尺寸·大小

一般使用ContentSizeFitter组件自动变更大小 API 渲染前 Vector2 GetPreferredValues(string text)Vector2 GetPreferredValues(string text, float width, float height)Vector2 GetPreferredValues(float width, float height) 渲染后 Vector2 GetRenderedValues()Vector…...

Sonar下启动发生错误,elasticsearch启动错误

Download | SonarQube | Sonar (sonarsource.com) 1.首先我的sonar版本为 10.4.1 &#xff0c;java版本为17 2.sonar启动需要数据库,我先安装了mysql, 但是目前sonar从7.9开始不支持mysql&#xff0c;且java版本要最少11,推荐使用java17 3.安装postsql,创建sonar数据库 4.启…...

Git常用命令以及异常信息汇总

常用命令&#xff1a; 查看本地分支&#xff1a; git branch 创建一个新仓库 git clone 仓库地址xxxxx cd 目标目录 git switch -c main touch README.md git add README.md git commit -m "add README" git push -u origin main 推送现有文件夹 cd 目标目录 git in…...

解释Python中的RESTful API设计和实现

解释Python中的RESTful API设计和实现 RESTful API&#xff0c;即符合REST&#xff08;Representational State Transfer&#xff0c;表述性状态转移&#xff09;架构风格的Web服务接口&#xff0c;已成为现代Web应用程序通信的标准。Python作为一种灵活且强大的编程语言&…...

一、Nginx部署

Nginx部署 一、Docker部署1.复制Nginx配置文件2.启动Nginx容器 一、Docker部署 1.复制Nginx配置文件 # 1.拉取镜像 docker pull nginx # 2.启动nginx容器 docker run --restartalways --namenginx -p 80:80 -d nginx # 3.宿主机创建挂载目录 mkdir /root/docker/nginx -p # 4…...

C语言基础---指针的基本语法

概述 内存地址 在计算机内存中&#xff0c;每个存储单元都有一个唯一的地址(内存编号)。通俗理解&#xff0c;内存就是房间&#xff0c;地址就是门牌号 指针和指针变量 指针&#xff08;Pointer&#xff09;是一种特殊的变量类型&#xff0c;它用于存储内存地址。指针的实…...

记录--病理切片图像处理

简介 数字病理切片&#xff0c;也称为全幻灯片成像&#xff08;Whole Slide Imaging&#xff0c;WSI&#xff09;或数字切片扫描&#xff0c;是将传统的玻片病理切片通过高分辨率扫描仪转换为数字图像的技术。这种技术对病理学领域具有革命性的意义&#xff0c;因为它允许病理…...

Android使用shape属性绘制边框内渐变色

目录 先上效果图实现方法shape属性介绍代码结果 先上效果图 这是使用AndroidStudio绘制的带有渐变色的边框背景色 实现方法 项目中由于UI设计需求&#xff0c;需要给按钮、控件设置带有背景色效果的。以下是UI效果图。 这里我们使用shape属性来绘制背景效果。 shape属性介…...

分类算法(数据挖掘)

目录 1. 逻辑回归&#xff08;Logistic Regression&#xff09; 2. 支持向量机&#xff08;Support Vector Machine, SVM&#xff09; 3. 决策树&#xff08;Decision Tree&#xff09; 4. 随机森林&#xff08;Random Forest&#xff09; 5. K近邻&#xff08;K-Nearest …...

scaling laws for neural language models

关于scaling law 的正确认识 - 知乎最近scaling law 成了最大的热词。一般的理解就是&#xff0c;想干大模型&#xff0c;清洗干净数据&#xff0c;然后把数据tokens量堆上来&#xff0c;然后搭建一个海量H100的集群&#xff0c;干就完了。训练模型不需要啥技巧&#xff0c;模型…...

水经微图IOS版5.2.0发布

随时随地&#xff0c;微图一下&#xff01; 水经微图&#xff08;简称“微图”&#xff09;IOS新版已上线。 在该版本中主要新增图层树节点排序功能、常规&#xff08;矩形、圆、椭圆、扇形&#xff09;绘制功能、地形夸张等主要功能。 当前版本 当前版本号为&#xff1a;5…...

聚观早报 | 哪吒L上市定档;iPhone 16最新高清渲染图

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 4月10日消息 哪吒L上市定档 iPhone 16最新渲染图 华为太空表与问界M9联动 蔚来万里长城加电风景线正式贯通 Red…...

【C++】手搓 list 容器

送给大家一句话&#xff1a; 若结局非你所愿&#xff0c;就在尘埃落定前奋力一搏。—— 《夏目友人帐》 手搓 list 容器 1 前言1.1 底层结构1.2 使用场景1.3 功能简介 2 框架搭建2.1 节点类2.2 list 类2.3 迭代器类 3 功能实现3.1 begin() 与 end()3.2 插入操作3.3 删除操作3…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...