【Java基础】CAS (Compare And Swap) 操作

news2024/11/17 3:43:05

关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。

目录

  • 一、导读
  • 二、概览
  • 三、使用场景
  • 四、原理
  • 五、优劣
    • 5.1 缺点:
    • 5.2 优点
  • 六、 推荐阅读

一、导读

我们继续总结学习Java基础知识,温故知新。

二、概览

CAS其实就是Compare And Swap的一个缩写,顾名思义就是比较并交换,其实就是把当前值与你预期的值进行一个比较,是一种用于在多线程环境下实现同步功能的机制。

CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。
在这里插入图片描述

CAS是原子性的操作(读和写两者同时具有原子性),是让CPU比较内存中某个值是否和预期的值相同,如果相同则将这个值更新为新值,不相同则不做更新.
对比交换是一条CPU的原子指令,其实现方式是基于硬件平台的汇编指令

CAS操作是原子性的,所以多线程并发使用CAS更新数据时,可以不使用锁。

使用volatile关键字可以保证可见性和有序性,但是却没有原子性,比如a++,引入cas就可以解决多线程的原子性问题。

CAS配合volatile来实现许多高并发类
在这里插入图片描述

三、使用场景

Java中利用CAS的乐观锁、原子性的特性高效解决了多线程的安全性问题。

CAS这种方式适用于并发量不高的情况。

四、原理

实现方式是通过借助C/C++调用CPU指令完成的,是一条CPU的原子指令,依赖于系统。

CAS的实现主要在JUC中的atomic包,存放在 java.util.concurrent.atomic 类路径下
如:自增长 AtomicInteger 等

Java中的CAS操作的执行依赖于Unsafe类,我们看下AtomicInteger的代码:

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    
    private volatile int value;
      
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    
}

CAS配合volatile来实现多线程可见性有序性和原子性。

再看下Unsafe类

    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

我们进入Unsafe类的native方法compareAndSwapInt,调用UnSafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令,这是一种完全依赖于硬件的功能,通过它实现了原子操作。

由于CAS是一种系统原语,原语属于操作系统用于范畴,是由若干条指令组成,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS操作是一条CPU的原子指令,不会造成所谓的数据不一致的问题,所以说CAS是线程安全的。

假如一个线程操作数据,干了一半活,累了,想要去休息。(貌似今天的线程体质都不太好)。于是它记录下当前数据的状态(就是数据的值),回家睡觉了。 醒来后打算继续接着干活,但是又担心数据可能被修改了,于是就把睡觉前保存的数据状态拿出来和现在的数据状态比较一下,如果一样,说明自己在睡觉期间,数据没有被人动过(当然也有可能是先被改成了其它,然后又改回来了,这就是ABA问题了),那就接着继续干。如果不一样,说明数据已经被修改了,那之前做的那些操作其实都白瞎了,就干脆放弃,从头再重新开始处理一遍。

所以CAS这种方式适用于并发量不高的情况,也就是数据被意外修改的可能性较小的情况。如果并发量很高的话,你的数据一定会被修改,每次都要放弃,然后从头再来,这样反而花费的代价更大了,还不如直接加锁呢。

五、优劣

5.1 缺点:

  1. 循环时间长开销大(CAS自旋操作):当内存地址V与预期值B不相等时会一直循环比较,直到相等
  2. 只能保证一个共享变量的原子操作,不能保证代码块的原子性。
  3. 存在ABA问题

并发1(上):获取出数据的初始值是A,后续计划实施CAS乐观锁,期望数据仍是A的时候,修改才能成功
并发2:将数据修改成B
并发3:将数据修改回A
并发1(下):CAS乐观锁,检测发现初始值还是A,进行数据修改
并发1在修改数据时,虽然还是A,但已经不是初始条件的A了,
中间发生了A变B,B又变A的变化,此A已经非彼A,数据却成功修改,
可能导致错误,这就是CAS引发的所谓的ABA问题。

优化ABA问题:
“版本号”的比对,一个数据一个版本,版本变化,即使值相同,也不应该修改成功。
很好解决,再加一个版本号字段就行了,并规定只要修改数据,必须使版本号加1。

5.2 优点

  • 没有引用锁的概念,并发量不高情况下提高效率
  • 减少线程上下文切换

六、 推荐阅读

【Java基础】原子性、可见性、有序性

【Java基础】java可见性之 Happens-before

【Java基础】java-android面试Synchronized

【Java基础】java-android面试-线程状态

【Java基础】线程相关

【Java基础】java 异常

【Java基础】java 反射

【Java基础】java 泛型

【Java基础】java注解

【Java基础】java动态代理

【Java基础】Java SPI

【Java基础】Java SPI 二 之 Java APT

【Java基础】 jvm 堆、栈、方法区 & java 内存模型

【Java基础】volatile关键字

【Java基础】CountDownLatch

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

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

相关文章

【Linux之拿捏信号2】核心转储文件core dump

文章目录 核心转储文件的概念ulimit命令Term和core 核心转储文件的概念 Linux系统级别提供了一种能力,在一个进程出现异常的时候,OS可以将该异常进程的核心代码部分进行核心转储,将内存中进程的相关代码数据,全部dump到磁盘中&am…

飞桨出海!百度飞桨携手联合国教科文组织共促全球高等教育数字化进程

百度飞桨响应联合国教科文组织,积极践行“共商、共建、共享”的全球合作理念,紧跟全球教育创新的步伐,推出面向全球高校教学人员的微认证英文课程——《AI科普与零代码实践》。百度基于丰厚的人工智能技术沉淀打造了本系列课程,携…

DRF+Vue.JS前后端分离项目实例(上):使用 Django-Rest-Framework快速实现 RESTful API 接口编程

1. RESTFul API 接口需求及设计 本文以学生信息查询功能为例,采用前后端分离架构,要求后端提供RESTFul 接口。 1.1 本例要求提供如下查询功能: 列表查询、单条查询添加学生信息更改学生信息删除学生信息 1.2 数据库student表结构如下&…

2.3 Web应用 -1 web 应用概述

2.3 Web应用 -1 web 应用概述 Web与HTTPHTTP协议概述 Web与HTTP World Wide Web: Tim Berners-Lee 网页网页互相链接 网页(Web Page)包含多个对象(objects) 对象:HTML文件、JPEG图片、视频文件、动态脚本等基本HTML文件:包含对其他对象引用的链接 对象的…

ValueError: No engine for filetype: ‘‘

目录 pandas 导出数据时报错 解决办法 很简单的原因,一开始我直接百度,发现没有搜到结果,在此记录一下 保存时,文件名结尾没加xlsx!!! 保存其他格式时,文件名里也要记得加上对应后缀…

【C语言进阶(五)】指针进阶详解(上)

💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C语言学习分享⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习更多C语言知识   🔝🔝 指针进阶 1. 前言 2. 字符指针 2.…

一个 NPM 包,帮助数十万程序员提高数十倍效率,难道不开源出来?(一)

我就知道你会点进来看看,吹牛逼的,哈哈,不过呢,我正在朝着这个方向前进,希望大家给我鼓励鼓励,希望点击进来小伙伴点点赞,点点关注。 说实话,写这个项目的目的,从我自己写…

ANSYS ACT插件开发基本流程

开发实施路线 以ACT仿真向导的开发为例,整体可以分为IronPython脚本开发和XML界面开发两个阶段;实际上所有的ANSYS产品的仿真向导开发都是遵循相同的路线流程。此外,另外两种类型的ACT插件开发路线亦是如此。 如何去学习 脚本开发是ACT插件…

再度进化,ChatGLM2-6B详细学习实践记录与资料分享

ChatGLM-6B是清华大学基础研究团队前一段时间开源出来的大模型,一经推出就得到了广泛的使用和推广,在我前面的博文中结合我自己的学习实践经历,已经详细的总结记录了一下,感兴趣或者是有需要的朋友可以自行获取即可,如…

【Linux】-Linux基本指令

作者:学Java的冬瓜 博客主页:☀冬瓜的主页🌙 专栏:【Linux】 分享: 屋檐如悬崖 风铃如沧海 我等燕归来 时间被安排 演一场意外 你悄然走开 故事在城外 浓雾散不开 看不清对白 你听不出来 风声不存在 是我在感慨 梦想来是谁在窗台 …

初步尝试调试postgresql源码

准备用VS2005和postgresql 8.x或9.0,搭建源码调试环境; 不成功;结果如下; 把下面文件中用#连着注释掉7行,然后加上一句 $self->{vcver} 8.00; 得到上面结果;如果不改的话上面的结果也没有;…

恒生电子探路金融大模型

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 近日,恒生电子和旗下子公司恒生聚源正式发布基于大语言模型技术打造的数智金融新品:金融智能助手光子和全新升级的智能投研平台WarrenQ。此外,恒生电子金融行业大模型LightGPT也首次对外亮…

硬件电路设计--运算放大器(三)应用一

文章目录 前言示例1示例2 一、反向比例反向比例改进版对平衡电阻R的讨论 二、同向比例三、电压跟随器四、加法运算电路4.1 反向加法电路4.2 同加法电路4.3 特殊应用 五、减法运算电路六、积分电路七、微分电路八、对数和指数运算电路8.1 对数8.2 指数 九、测量放大电路&#xf…

基于matlab根据一系列图像估计单个校准相机的轨迹(附源码)

一、前言 视觉里程计是通过分析一系列图像来确定相机的位置和方向的过程。视觉里程计用于各种应用,例如移动机器人、自动驾驶汽车和无人机。此示例说明如何根据一系列图像估计单个校准相机的轨迹。 此示例演示如何从一系列二维视图估计校准相机的轨迹。此示例使用…

常用字符串处理方法汇总--Pandas

字符串处理只能在Series上进行,不可以在DataFrame上操作,只能对字符串进行处理,不能对整数、日期进行处理 1. 元素统计 1.1 str.count() 1.1.1 函数功能 统计Series中每个元素中包含pat的次数 1.1.2 函数语法 Series.str.count(pat, fl…

美日韩限制光刻机供应,中国正式亮剑,外媒:轮到美芯被卡脖子了

这几年美国频频对中国芯片采取措施,今年以来美国更是变本加厉,联合荷兰和日本限制对中国出售光刻机等芯片设备,试图将中国的芯片工艺限制在45纳米以上,近日我国商务部联合海关等部门宣布对镓、锗等稀有金属实施出口限制&#xff0…

Python实现某只股票的MACD、KDJ指标的单双金叉点判定

金叉理论介绍 在股票K线图中,短期的收盘价均线向上穿越长期均线即为金叉,但如果长期均线向下或变缓,同时短期均线向上穿越就不能称之为金叉。 对于MACD指标,若差离值线由下向上突破移动平均线,即DIF值前一天小于DEA值…

MySQL库表操作的作业

1.创建数据库 create database Market; mysql> show databases; -------------------- | Database | -------------------- | information_schema | | Market | | db1 | | mysql | | performance_schema | | …

消息队列 - RocketMQ

1. 名词解释和概念 NameServer: 是一个无状态节点,可集群部署,节点之间无任何信息同步用于服务注册和发现,为 MQ 集群提供服务协调与治理记录并维护 Topic 和 Broker 的信息为生产者和消费者提供 Topic 的路由信息 无状态和有状…

On the Properties of Neural Machine Translation: Encoder–DecoderApproaches

摘要 Neural machine translation : 神经机器翻译。 神经机器翻译模型经常包含编码器和解码器:an encoder and a decoder. 编码器: 从一个变长输入序列中提取固定长度的表示。a fixed-length representation. 解码器:从表示中…