深入解析CAS的原理机制

一、基本概述

1.1 引入背景

例:i++。假设由线程A和B需要对i进行加1的操作。线程A和线程B会分别从主内存中读取i值到自己的工作内存中。原本相加之后的值为3,但线程A和线程B分别加1后将值刷新到主内存,发现主内存的值为2,出现错误。

1.2 解决方法

保证线程A改写共享变量的操作是原子性(不能被中断的一个或一系列操作)的。采用CAS失败重试机制。

1.3 CAS(V,E,N)

1. V代表需要读写的内存位置(工作内存)
2. E代表进行比较的预期原值(主内存)
3. N代表打算写入的新值

具体流程:
假设线程A和B读取的i为2,那么线程A使用CAS操作时,会从工作内存中取出i值2与主内存中的值进行比较,发现与主内存中的值是相同的,则执行更新操作,并把值刷新到主内存中,主内存中的i值为3。线程B需要执行i加1的操作,发现工作内存中的i值2与主内存中的i值3是不一样,更新失败。然后会重新从主内存中取值到工作内存,再执行更新操作,直到成功。
由于每次都需要和主存中的最新值进行比较,比较需要结合volatile一起使用

1.4 特点

结合CAS和volatile可以实现无锁并发,适用于线程数较少,且多核CPU的场景下。

  • CAS是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃亏点再重试呗。
  • synchronized是基于悲观锁的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了锁你们都别想改,我改完了解开锁,你们才有机会。

CAS体现的是无锁并发、无阻塞并发:

  1. 由于没有使用synchronized,线程不会阻塞;
  2. 如果竞争激烈,重试必然频繁发生,会影响效率。

二、底层原理

2.1 具体实现

底层使用的是Unsafe类。Unsafe对象提供了操作内存、线程的的方法,Unsafe不能直接被调用,只能通过反射调用

Unsafe只提供了3CAS方法:compareAndSwapObject、compareAndSwapInt、compareAndSwapLong. 

AtomicBoolean流程:

  1. 先把Boolean转换成整形;
  2. 使用compareAndSwapInt进行CAS。

源码如下,则char、float和double变量也适用类似的思路来实现:

public final boolean compareAndSet(boolean expect, boolean update) { 
    int e = expect ? 1 : 0; int u = update ? 1 : 0; 
    return unsafe.compareAndSwapInt(this, valueOffset, e, u); 
} 
AtomicInteger atomicInteger = new AtomicInteger(2020); 
System.out.println(atomicInteger.compareAndSet(2020,2021)); 

2.2 实现类为AtomicInteger

public class AtomicInteger extends Number implements java.io.Serializable
// 表示变量value在AtomicInteger实例对象内的内存偏移量
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; 
static { 
    try { 
        valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); 
    } catch (Exception ex) { 
        throw new Error(ex); 
    } 
} private volatile int value; 

在这里插入图片描述
在这里插入图片描述

2.3 存在的问题

  1. 循环开销大:如果线程自旋CAS长时间不成功,会给CPU带来非常大的执行开销
  2. 一次性只能保证一个共享变量的原子性,无法保证操作多个共享变量时的原子性。
解决方法:
1. 加锁;
2. 把多个共享变量合并成一个共享变量来操作,Java提供了AtomicReference类来保证引用对象之间的原子性,即多个共享变量放在一个对象里来操作。
  1. ABA问题
    ● 如果一个值原来是A,变成了B,最后又变成了A,那么使用CAS检查时发现它的值没有变化,但实际上却变化了。
    解决方法: 使用版本号,在变量前面加上版本号。使用Java提供的AtomicStampedReference来解决ABA问题。具体过程:1.先检查当前引用是否为预期引用;2.并且检查当前标志是否为预期标志(双重检查)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学c还行,学Python很累,还有其他语言适合我吗?

学c还行,学Python很累,还有其他语言适合我吗? 在开始前我分享下我的经历,我刚入行时遇到一个好公司和师父,给了我机会,一年时间从3k薪资涨到18k的, 我师父给了一些 电气工程师学习方法和资料&a…

新建项目module,但想归到一个目录下面

1. 想建几个module, 例如 component-base-service,component-config-service, 但是module多了会在CloudAction下面显示很多目录, 所以想把它们归到components模块下面去, 类似于下图的效果 2. 创建过程 右击CloudAction 新建 module -> 选maven类型 输入components, 建成后删…

【目标检测经典算法】R-CNN、Fast R-CNN和Faster R-CNN详解系列二:Fast R-CNN图文详解

RCNN算法详解:【目标检测经典算法】R-CNN、Fast R-CNN和Faster R-CNN详解系列一:R-CNN图文详解 学习视频:Faster RCNN理论合集 Fast RCNN 概念辨析 1. RoI 在Fast R-CNN中,RoI(Region of Interest,感兴…

Spring多线程事务处理

一、背景 本文主要介绍了spring多线程事务的解决方案,心急的小伙伴可以跳过上面的理论介绍分析部分直接看最终解决方案。 在我们日常的业务活动中,经常会出现大规模的修改插入操作,比如在3.0的活动赛事创建,涉及到十几张表的插入…

使用DateUtil工具类偏移日期

使用DateUtil工具类偏移日期 一、依赖二、源码三、示例代码 一、依赖 <!--工具依赖--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version></dependency>二、源码 …

Python常用图片数据方法

文章目录 1. 常用图片数据类型2. 图片的显示2.1 plt.imshow()2.2 使用 turtle 来绘制图片 3.图片ndarray数据的常用切片操作使用 cv2 来读取图片打印数据R G B 通道的获取BGR 转成 RGBcv2 不支持中文路径的解决方法 4 PIL.Image 转成 QImage 或 QPixmap 1. 常用图片数据类型 使…

Android基础开发-通讯录的添加和查询

案例&#xff1a;往手机通讯录添加信息&#xff0c;输入姓名和手机号。 保存的手机的表&#xff1a;一共有两个&#xff0c;一个是主表&#xff0c;提供一个联系人id&#xff0c;另外是辅表&#xff0c;提供id对应的手机号和姓名。 普通操作&#xff1a;一个表一个表的添加 …

【黑马程序员】python函数

文章目录 函数什么是函数为什么学习函数函数定义函数的传入参数函数的返回值返回值基础None返回值 函数说明文档函数的嵌套调用定义代码示例 全局变量和局部变量全局变量global变量局部变量 函数综合案例 函数 什么是函数 组织好的&#xff0c;可重复使用的、用来实现特定功能…

【每日八股】Java基础经典面试题2

前言&#xff1a;哈喽大家好&#xff0c;我是黑洞晓威&#xff0c;25届毕业生&#xff0c;正在为即将到来的秋招做准备。本篇将记录学习过程中经常出现的知识点以及自己学习薄弱的地方进行总结&#x1f970;。 本篇文章记录的Java基础面试题&#xff0c;适合在学Java基础的小白…

设计模式系列之-策略模式(优化过多代码if…else)

首先解释下什么策略模式 如下图&#xff1a; 简而言之&#xff1a;算法的使用与算法的实现分离开来 想象有一个开关按钮&#xff0c;每次按下去都可以切换不同的灯光模式&#xff08;例如&#xff1a;强光、柔光、闪烁&#xff09;&#xff0c;这里的每种灯光模式就是一个策略…

程序人生——Java中基本类型使用建议

目录 引出Java中基本类型使用建议建议21&#xff1a;用偶判断&#xff0c;不用奇判断建议22&#xff1a;用整数类型处理货币建议23&#xff1a;不要让类型默默转换建议24&#xff1a;边界、边界、还是边界建议25&#xff1a;不要让四舍五入亏了一方 建议26&#xff1a;提防包装…

Unity类银河恶魔城学习记录8-5 p81 Blackhole duration源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码、 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Blackhole_Skill_Controller.cs using System.Collections; using Syste…

UL1642标准_锂聚合物电池亚马逊测试报告

UL1642标准_锂聚合物电池亚马逊测试报告 什么是锂聚合物电池UL1642标准&#xff1f; UL1642 认证要求涵盖旨在用于技术人员可更换或用户可更换应用的锂离子电池。UL1642 认证要求是为了避免锂离子电池在产品中工作时发生火灾或爆炸的风险。 锂聚合物电池 UL是Underwriters L…

Devin:首位人工智能软件工程师的介绍

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

2024春招看了上百份程序员简历,这个工具写的简历最好!(附模板)

你们在制作简历时&#xff0c;是不是基本只关注两件事&#xff1a;简历模板&#xff0c;还有基本信息的填写。 当你再次坐下来更新你的简历时&#xff0c;可能会发现自己不自觉地选择了那个“看起来最好看的模板”&#xff0c;填写基本信息&#xff0c;却没有深入思考如何使简历…

DataWhale公开课笔记2:Diffusion Model和Transformer Diffusion

Stable Diffusion和AIGC AIGC是什么 AIGC的全称叫做AI generated content&#xff0c;AlGC (Al-Generated Content&#xff0c;人工智能生产内容)&#xff0c;是利用AI自动生产内容的生产方式。 在传统的内容创作领域中&#xff0c;专业生成内容&#xff08;PGC&#xff09;…

Python数值方法在工程和科学问题解决中的应用

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 随着计算机技术的不断发展&#xff0c;Python作…

UI设计中的图标的分类,功能性图标

图标的分类 既然知道了图标的作用和重要性&#xff0c;那么接下来&#xff0c;就要进一步了解在工作中我们要设计哪些图标。图标可以划分成三种大类:功能性图标、装饰性图标、启动图标。 功能性图标 功能图标是具有指代意义且具有功能标识的图形&#xff0c;它不仅是一种图形&a…

代码随想录算法训练营第day41|背包理论基础、416. 分割等和子集

目录 a.背包理论基础——01背包 1.二维数组的01背包表示 2.一维滚动数组表示 b. 416. 分割等和子集 - 力扣&#xff08;LeetCode&#xff09; a.背包理论基础——01背包 背包问题分类&#xff1a; 对于面试的话&#xff0c;其实掌握01背包&#xff0c;和完全背包&#xff…

Sharding sphere分库分表

需要物理自己实现分表分库&#xff0c;然后通过配置文件配置。 配置文件&#xff1a; 需要配置多个数据源&#xff0c;主从表的关系【默认主表修改&#xff0c;从表读取】&#xff0c;定义分库的策略【比如User id】和分表【表Id】的策略 分库和分表策略&#xff1a;分库策略…