CAS、Synchronized 原理

news2025/1/11 14:58:05

    • 什么是CAS
    • CAS应用
      • 原子类
      • 自旋锁
      • CAS的ABA问题
    • Synchronized 原理
      • 锁升级优化
      • 锁消除优化
      • 锁粗化优化

什么是CAS

什么是CAS?Compare and swap :比较和交换

一个CAS操作涉及:
我们假设内存中的原数据V,旧的预期值A,需要修改的新值B。

  1. 比较 A 与 V 是否相等。(比较)
  2. 如果比较相等,将 B 写入 V。(交换)
  3. 返回操作是否成功。
    在这里插入图片描述
    上述过程:如果V和A不同;啥问题也没有;不操作;CAS的特殊之处;把上述操作通过一个CPU指令完成;效率非常高;这个操作原子性的。可以认为CPU提供的特殊指令;回避线程安全问题。
    可以理解:比较是一个原子性操作;交换也是一个原子性操作。如果比较相等那么比较和交换的整体也是一个原子性操作。
    当多个线程同时对某个资源进行CAS操作,只能有一个线程操作成功,但是并不会阻塞其他线程,其他线程只会收到操作失败的信号。可以认为是乐观锁的一种实现。

CAS应用

原子类

CAS实现原子类;例如:Java标准库提供的原子类AtomicInteger
AtomicInteger atomicInteger = new AtomicInteger(0);
atomicInteger.getAndIncrement();//相当于++操作;多线程在++操作就是安全的

假设在多线程进行这个++操作:伪代码
在这里插入图片描述
执行过程:
1:先把内容读取到自己的栈内存上(cpu寄存器)
在这里插入图片描述

2:假设线程1先执行CAS操作.由于oldValue和value的值相同,直接进行对value赋值。CAS是直接读写内存的,而不是操作寄存器;CAS的读内存,比较,写内存操作是一条硬件指令,是原子性。

3::写完后的结果如下
在这里插入图片描述
4:线程2再执行CAS操作,第一次CAS的时候发现写入失败;因为oldValue和value不相等。因此需要进入循环;在循环里重新读取value的值赋给oldValue。重复上述流程
上述使用一个原子类.不需要使用重量级锁,就可以高效的完成多线程的自增操作.

自旋锁

伪代码:
通过 CAS 操作检查当前锁是否被其他线程持有。如果锁已经被持有,CAS 操作会失败,进入自旋等待状态。
如果锁没有被其他线程持有,CAS 操作成功,将当前线程设为锁的持有者(owner)。
这是一个典型的自旋锁实现,会一直循环检测直到成功获取锁。

public class SpinLock {
    private Thread owner = null;

    public void lock() {
        // 通过CAS(Compare and Swap)检查当前锁是否被某个线程持有。
        // 如果这个锁已经被其他线程持有,则自旋等待。
        // 如果这个锁没有被其他线程持有,则将owner设为当前尝试加锁的线程。
        while (!CAS(this.owner, null, Thread.currentThread())) {
            // 自旋等待,直到成功获取锁
        }
    }

    public void unlock() {
        // 释放锁,将owner设为null
        this.owner = null;
    }
}

CAS的ABA问题

CAS 在运行中的核心,检查 value 和 oldvalue 是否一致如果一致;就视为 vaue 中途没有被修改过,所以进行下一步交换操作是没问题的。
上述的一致有两种可能:这里 一致,可能是没改过。也可能是,改过,但是还原回来了(ABA问题)。

ABA问题是特殊情况;但是仍然是致命的;假设有CAS方式扣款;判断这个钱扣了没;你银行卡有1000块钱要取500。
现在两个线程读到你余额是1000情况;然后你取的时候有人给你转了500。这会就会线程1这个扣完;然后线程3又充500;线程2接着扣。

怎么解决呢?
想象成,初始版本号是 1,每次修改版本号都 + 1然后进行 CAS 的时候不是以金额为基准了,而是以版本号为基准。版本号只能升;不能降;只要版本号没变就一定没发生改变;这个问题得我们自己去避免。基于版本号实现的乐观锁是一种典型的实现方式。

Synchronized 原理

jdk1.8下

  1. 开始时是乐观锁, 如果锁冲突频繁, 就转换为悲观锁.
  2. 开始是轻量级锁实现, 如果锁被持有的时间较长, 就转换成重量级锁.
  3. 实现轻量级锁的时候大概率用到的自旋锁策略
  4. 是一种不公平锁
  5. 是一种可重入锁
  6. 不是读写锁
    JVM 将 synchronized 锁分为无锁、偏向锁、轻量级锁、重量级锁状态。会根据情况,进行依次升级。有很多内部优化机制让这个锁更高效和好用。

锁升级优化

synchronized (locker) { }过程:
1:无锁状态;初始阶段,对象的标记为无锁状态。当第一个线程进入synchronized代码块时,它会尝试获取锁,此时这个对象的标记变为偏向锁。
2:偏向锁;进行加锁的时候,首先先会进入到偏向锁状态;偏向锁,并不是真正的加锁,而只是占个位置;有需要再真加锁,如果后续没有其他线程来竞争该锁, 那么就不用进行其他同步操作了(避免了加锁解锁的开销)。跟做个标记一样;然后清空标记。
3:轻量级锁状态: 当发生锁竞争,偏向锁会升级为轻量级锁。synchronized相当于自旋的方式加锁(跟上述CAS伪代码逻辑一样),并尝试使用CAS来争夺锁。
4:重量级锁状态: 如果要是很快别人就释放锁了,自旋是划算的,但是如果迟迟拿不到锁,一直自旋,并不划算.synchronized 自旋不是无休止的自旋,自旋到一定程度之后,就会再次升级成 重量级锁(挂起等待锁;)
可以想象是有个计数器记录循环多少次;循环多久;然后到一定程度结束循环执行重量级锁的逻辑;让其先放弃cpu;当前线程一旦被切换cpu就是比较低效的事情;因为即使对方释放锁了;你这边也得要等待到你调度的时候;谁能保证猴年马月。

注意:锁只能这样子升级;不会降级;重入的情况呢?synchronized对重入的情况是特殊处理;不加锁;只是计数。

锁消除优化

编译器智能的判定,看当前的代码是否是真的要加锁,如果这个场景不需要加锁,程序猿也加了,就自动把锁给去掉。
比如:StringBuffer sb = new StringBuffer();是线程安全的;底层是synchronized保证的。但是单线程你并不会用到线程安全问题;所以就是我们使用StringBuffer和StringBudder通常混用不区分。
sb.append(“a”);
sb.append(“b”);
sb.append(“c”);
sb.append(“d”);

锁粗化优化

锁的粒度: synchronized 包含的代码越多,粒度就越粗包含的代码越少,粒度就越细。有时候并不是锁的粒度越细越好。
一般情况下认为是锁的粒度细一点好;这样子并发的块就比较多;但是有些两次加锁解锁之间,间隙非常小此时莫不如就直接一次大锁好;因为反复的加锁和解锁会消耗更多资源。(间隙特别小;就算并发也作用不大;并发减少的时间;不如加锁的开销大。)

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

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

相关文章

第六十一周周报

学习目标: 代码 实验 论文 学习时间: 2023.11.4-2023.11.10 学习产出: 代码 1、修改CelebA64数据集的代码,实验暂时没跑完 2、添加CB模块,实验暂时没跑完 3、修改ViTGAN的CIPS Generator位置编码为傅里叶编码 …

【LeetCode笔试题】26.删除有序数组中的重复项

问题描述 给你一个非严格递增排列的数组nums,请你原地删除重复出现的元素,使每个元素只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持一致。然后返回nums中唯一元素的个数。 考虑nums的唯一元素的数量为k,你需要…

FPGA与STM32_FSMC总线通信实验

FPGA与STM32_FSMC总线通信实验 内部存储器IP核的参数设置创建IP核FPGA代码STM32标准库的程序 STM32F407 上自带 FSMC 控制器,通过 FSMC 总线的地址复用模式实现STM32 与 FPGA 之间的通信,FPGA 内部建立 RAM 块,FPGA 桥接 STM32 和 RAM 块&…

面向对象--------三巨头

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ ა 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶个人主页&am…

后台管理系统实用提示框,JavaScript实现(成功,失败,提示弹窗)

本篇就给大家分享一下超级好用的JavaScript提示框,使其开发中节省大量代码!!! 由于本篇运用到了jQuery技术,所以在写之前一定记得引入jQuery库 目录 首先呢我们需要创建html元素 设置css样式,直接引入…

【华为OD:C++机试】Day-4

目录 🌷1. 排队游戏: 🌷2. 购物: 🌷3. 划分字符串: 🌷4. MELON 的难题: 🌷5. 荒岛求生: 🌷6. 通过软盘拷贝文件: 🌷7. 数字…

基于springboot乐器视频学习网站设计与实现(源码齐全可用)

项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…

Linux常用命令——bzmore命令

在线Linux命令查询工具 bzmore 查看bzip2压缩过的文本文件的内容 补充说明 bzmore命令用于查看bzip2压缩过的文本文件的内容,当下一屏显示不下时可以实现分屏显示。 语法 bzmore(参数)参数 文件:指定要分屏显示的.bz2压缩包。 在线Linux命令查询…

使用JavaScript编写游戏平台数据爬虫程序

目录 一、引言 二、准备工作 三、爬取数据 四、数据处理与存储 五、数据分析与利用 六、结论与展望 一、引言 随着网络技术的发展,数据已经成为企业、研究机构和个人的重要资源。数据可以帮助我们了解市场趋势、用户需求,甚至可以用于机器学习和人…

代码随想录图论部分-695. 岛屿的最大面积|1020. 飞地的数量

695. 岛屿的最大面积 题目:给你一个大小为 m x n 的二进制矩阵 grid 。岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水&#xff0…

什么是安全平行切面

安全平行切面的定义 通过嵌入在端—管—云内部的各层次切点,使得安全管控与业务逻辑解耦,并通过标准化的接口为安全业务提供内视和干预能力的安全基础设施。安全平行切面是一种创新的安全体系思想,是实现“原生安全”的一条可行路径。 为什…

Milvus Cloud——LLM Agent 现阶段出现的问题

LLM Agent 现阶段出现的问题 由于一些 LLM(GPT-4)带来了惊人的自然语言理解和生成能力,并且能处理非常复杂的任务,一度让 LLM Agent 成为满足人们对科幻电影所有憧憬的最终答案。但是在实际使用过程中,大家逐渐发现了通…

Postman模拟上传文件

如图,在F12抓到的上传文件的请求 那要在postman上模拟这种上传,怎么操作呢,如图,选中【Select File】选取文件上传即可

【CASS精品教程】cass3d加载点云(.ilas)并处理应用

本文讲解cass11.0 3d中将ilas点云转为las加载并进行后续处理。(cass11.0下载与安装) 一、ilas点云格式介绍 点云ilas格式是现今数字化三维模型建模的--种普遍被使用的数据格式,也被称作点云、点集或聚集点。它把地球表面上的物体,比如森林、海洋、河流、山脉等自然物体,以…

【码银送书第十期】《强化学习:原理与Python实战》

目录 1.什么是人工智能对齐 2.为什么要研究人工智能对齐 3.人工智能对齐的常见方法 1.什么是人工智能对齐 人工智能对齐(AI Alignment)指让人工智能的行为符合人的意图和价值观。 人工智能系统可能会出现“不对齐”(misalign)的…

Python喜羊羊

目录 系列文章 写在前面 绘图基础 画喜羊羊 写在后面 系列文章 序号文章目录直达链接表白系列1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏表白代码https://want595.blog.csdn.net/article/details/1297945183跳动的爱心https://want5…

elemetui 解决同个页面,同时使用多个el-table表格组件导致的数据错乱

1、背景 在一个页面中,使用了饿了么框架的3个el-table表格,3个表格平级,只不过是根据条件判断渲染哪个表格。本来以为使用v-if就可以隔离,没想到还是出现了问题,因为3个表格中有几列绑定的字段一模一样,导…

STM32基础--NVIC中断控制器

一、NVIC是什么? NVIC是一种中断控制器。当一个中断正在处理时,另一个更高优先级的中断可以打断当前中断的执行,并立即得到处理。这种机制使得处理器在高速运行的同时,能够及时响应不同优先级的中断请求。 二、有哪些优先级&…

如何在 Idea 中修改文件的字符集(如:UTF-8)

以 IntelliJ IDEA 2023.2 (Ultimate Edition) 为例,如下: 点击左上角【IntelliJ IDEA】->【Settings…】,如下图: 从弹出页面的左侧导航中找到【Editor】->【File Encodings】,并将 Global Encoding、Project E…

Excel函数 - 多条件查找查询公式

如下图所示,要求在H2单元格,根据A列序号和B列姓名,从表中查找对应的成绩。 1、Vlookup公式(数组公式) VLOOKUP(F2&G2,CHOOSE({1,2},A2:A7&B2:B7,C2:C7),2,0) 注:Excel最新版不需要按Ctrlshiftente…