Java并发基石——CAS是如何实现的?

news2024/7/6 18:23:09

目录

1. 什么是CAS?

2. Java中关于 CAS 的 API 在哪里?

3. CAS API方法和参数解析

 4. CAS的底层实现

5. CAS是如何保证多核线程安全的?

6. CAS的缺点?

7. 如何避免ABA问题?


1. 什么是CAS?

CAS的全程是 "CompareAndSwap",翻译过来就是 "比较和替换"。

CAS的操作包含三个操作数——内存地址,期望值,新值。如果内存位置的值与期望值匹配,那么处理器就会自动将该位置的值更新为新值;否则,处理器不做任何操作。无论哪种情况,它都会在CAS指令之前返回该位置的值。 

CAS可以理解为 "我认为位置V的值应该是A,如果有该值,则将B放在这个位置;否则,不更改该位置的值,只告诉我这个位置现在的值即可"。

2. Java中关于 CAS 的 API 在哪里?

Java中 CAS 的 API 方法定义在 sun.misc.Unsafe 类中,如下图所示中的三个方法,可以看到该类的名字叫 Unsafe(不安全的),三个方法都有 native 修饰,这些方法不是由 Java 语言编写的,而是由C语言编写的;总之记住一点就行了,这些 native 本地CAS方法是用C语言编写的,通常也不是让我们 Java 程序员去调用使用的,更多见到它们是在源码中碰到它们。

3. CAS API方法和参数解析

CAS的三个方法作用相似,它们都有四个参数,下面我来说一下它们的作用。

compareAndSwapObject:比较并交换 Object 类型数据;

compareAndSwapInt:比较并交换 Int 类型数据;

compareAndSwapLong:比较并交换 Long 类型数据;

var1:方法要操作的对象;

var2:方法要操作的对象中属性的偏移量(举个例子,我们有一个 User 用户对象,在堆中存放,但我们只获取该 User 对象的其中一个属性值,就需要通过偏移量来获取,例如 user.name 获取用户名称属性);

var3:表示想要修改的数据属性当前值(意思就是改之前是什么值);

var4:表示想要修改的数据的修改值(意思就是想改成什么值);

 4. CAS的底层实现

这里我来简单解释一下CAS的底层实现,CAS是通过调用JNI代码来实现的。

JNI 全称 java.native.interface ,翻译过来就是 Java本地接口方法,允许Java调用其它语言,而Java中的这三个CAS方法底层是用C语言编写的,通过C语言调用底层CPU,最终映射到CPU指令集上得以实现。

5. CAS是如何保证多核线程安全的?

现在的计算机大多都是多核心处理器,那么在此种情况下,系统执行CAS操作之前,会先去判断当前系统是否为多核心系统。如果是,就会给 "总线" 加锁,尽管有多个线程,但只有一个线程能给总线加锁成功,加完锁之后就会去执行CAS操作,也就是说CAS操作的原子性是平台级别的。而且只能有一个线程在同一时刻能够去执行CAS运算,无法多线程并行CAS操作,这样就解决了多核线程的安全问题。

6. CAS的缺点?

上面说到了CAS的操作原理,比较并替换,CAS操作时需要先判断先前的值是否发生变化,未变化则CAS,变化了则不执行CAS,如果说A线程在执行CAS操作之前,B线程将需要判断的值 a 改为了 b ,然后又从 b 改成了 a。那么当A线程再去执行CAS操作的时候,是可以执行成功的,因为它不管中间过程,只要我线程A在CAS时值未发生变化,就可以替换,但不能避免发生过变化不影响操作这种情况的发生。

举个简单的例子,事务A要去对数据库中的字段 num (假设当前值为1)做加一操作,事务B在事务A之前先去执行了加一操作,值变成了2,但是执行过程中发生了异常,事务B回滚,又从2回滚到了1,此时事务A再去对 num 进行加一操作时,是可以成功的,因为值没有发生改变。这种情况我们通常称为ABA问题。

7. 如何避免ABA问题?

为了解决ABA问题,在Java中,就引入了版本号这一说法,很简单,我们执行CAS操作时,不是会比较当前值和期望值是否相同吗?那我们就再加入一个版本号,对当前可能出现ABA问题的数据加上一个版本号,每当有一个线程对当前数据发生过修改,版本号都会做一次变换,即便又改回了原来的值,版本号也是不一致的。这样我们在执行CAS操作时,不仅要满足为当前值与期望值相等,还要满足当前版本号与期望版本号相同,只要有一个不同,CAS操作就不会成功,这样就可以避免ABA问题的出现。

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

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

相关文章

动态库静态库对比

程序编译成可执行程序的过程 静态在连接阶段会把代码复制到可执行文件中 动态则不,而是打包一些信息进去,在执行的时候根据信息找到动态库执行 制作过程 静态库 动态库 优缺点 库比较小且更新慢的时候一般使用静态,反之则动态 静态库 …

七种 BeanDefinition,各显其能!

聚沙成塔!不知不觉 Spring 源码已经连续更了两个月啦,视频也录制了不少了,对 Spring 源码分析感兴趣的小伙伴戳这里哦Spring源码应该怎么学?~ 今天我们继续来看 Spring 源码中一个非常重要的概念:BeanDefi…

万物皆可连的腾讯轻联

文章目录 前言关于腾讯轻联小试牛刀新建流程配置逻辑组件配置连接器流程上线 其它功能核心能力总结 前言 工作中有这样一个需求,每周五下午三点定时给小组内成员发送邮件,邮件内容固定,主要作用是提醒大家记得发周报;其实这个需求…

iOS:解决Could not find a storyboard named ‘LaunchScreen.storyboard‘ in bundle NSBundle

打开项目的:HBuilder-uniPlugin-Info.plist 删除Launch screen interface file base name 然后看图,清空掉之前的LaunchScreen.storyboard东西 再运行就可以了,我也是改自定基座出的问题略

西门子LAD编程扫描周期带来的步序跳转问题

一、程序目的 按一下启动,程序进入第一步。延时五秒之后进入第二步进行自加1,然后回到第一步继续延时5秒循环,依次类推。 二、出现的问题 第一次程序进入第一步时,定时器正常定时,计数正常加1,但从第二轮开…

使用WinDbg进行动态调试

前言 本文章主要介绍如何使用WinDbg进行动态调试。如果程序崩溃后,没有记录dump文件,或者程序启动时发生异常,比如常见的 应用程序无法正常启动(0xc000007b) 报错,都可以使用WinDbg动态调试功能来定位问题。文章最后,…

用go实现一个循环队列

目录 队列数组队列的“假溢出”现象循环队列三种判断队列空和满的方法无下标(链式)有下标(顺序)长度标记 go用顺序表实现一个循环队列队列的链式存储结构 队列 队列(queue)是只允许在一端进行插入操作&…

物联网世界的无线电报之MQTT详解

文章目录 1. 前言1.1. 物联网与MQTT的关系1.2. MQTT的重要性及应用场景 2. MQTT基础2.1. MQTT的定义与起源2.2. MQTT的工作原理2.3. MQTT的协议格式2.4. 用java造个轮子 3. 深入理解MQTT3.1. MQTT的主要组件3.1.1. Publisher(发布者)3.1.2. Subscriber&a…

RTSP流媒体服务器EasyNVR视频平台以服务方式启动异常却无报错,该如何解决?

EasyNVR是基于RTSP/Onvif协议的安防视频云服务平台,可实现设备接入、实时直播、录像、检索与回放、云存储、视频分发、级联等视频能力服务,可覆盖全终端平台(电脑、手机、平板等终端),在智慧工厂、智慧工地、智慧社区、…

【2023微博评论爬虫】用python爬上千条微博评论,突破15页限制!

文章目录 一、爬取目标二、展示爬取结果三、爬虫代码四、同步视频五、获取完整源码 您好,我是 马哥python说,一枚10年程序猿。 一、爬取目标 前些天我分享过一篇微博的爬虫: 马哥python说:【python爬虫案例】爬取微博任意搜索关…

【网络编程】IO多路复用

IO多路复用是一种高效的I/O处理方式,它允许单个进程能够同时监视多个文件描述符(sockets、文件等),并在其中任何一个文件描述符准备好进行I/O操作时进行处理。它的核心在于使用少量的线程或进程来管理多个I/O操作,以提…

【JavaSpring】spring接口-beanfactory和applicationcontext与事件解耦

beanfactory 1.applicationcontext的父接口 2.是Spring的核心容器 功能 表面只有getBean,但实现类默默发挥了巨大作用 1.管理所有bean 2.控制反转 3.基本的依赖注入 applicationcontext 功能 1.继承了MessageSource,有了处理国际化资源的能力 …

【C++】继承基础知识一遍过

目录 一,概念 二,继承定义 1. 继承格式 2. 访问限定符与继承方式的关系 3. 继承父类成员访问方式的变化 小结: 三. 父类与子类对象赋值转化 四,继承作用域 1.特点 2. 测试题 五,派生类不一样的默认成员函…

【nacos】2.1.1持续输出事件警告日志

nacos-server 2.1.1 持续输出事件警告日志,修复NamingTraceEvent连续打印日志。这是 2.1.1 beta 功能跟踪事件。如果没有订阅者处理TraceEvent,将打印此日志。2.1.1版本中忽略它,我们将在2.1.2版本中对其进行增强。 WARN There are no [com.alibaba.nac…

Linux系统中驱动之设备树的platform驱动实现

每日一个简单的驱动,日久方长,对Linux驱动就越来越熟悉,也越来容易学会写驱动程序。今日进行设备树下的platform设备驱动。 前面一篇我们讲解了传统的、未采用设备树的 platform 设备和驱动编写方法。最新的 Linux 内核已经支持了设备树&…

c语言练习45:模拟实现内存函数memcpy

模拟实现内存函数memcpy 针对内存块&#xff0c;不在乎内存中的数据。 拷贝内容有重叠的话应用memmove 模拟实现&#xff1a; 代码&#xff1a; 模拟实现memcpy #include<stdio.h> #include<assert.h> void* my_memcpy(void* dest, const void* src, size_t num…

【计算机基础知识3】IP 地址和子网掩码、DNS、HTTP

目录 前言 一、IP地址和子网掩码 1. IP地址的概念 2. IP地址的分类 3. 子网掩码的概念 4. 子网掩码的用途 二、域名系统&#xff08;DNS&#xff09; 1. DNS的作用 2. 域名解析过程 3. 如何配置和管理域名解析 三、HTTP&#xff08;超文本传输协议&#xff09; 1. H…

Pytest系列-测试用例前后置固件setup和teardown的介绍和使用(2)

简介 在unittest框架中&#xff0c;有两个前置方法&#xff0c;两个后置方法&#xff0c;还有两个模块方法&#xff0c;分别是 setup()&#xff1a;每个用例执行之前都会自动调用setupClass()&#xff1a;在类中所有的测试方法执行前会自动执行的代码&#xff0c;只执行一次t…

华为云中对象存储服务软件开发工具包(OBS SDK) C语言介绍

华为云的OBS介绍&#xff1a;摘自华为云官网&#xff1a;https://support.huaweicloud.com/obs/index.html 华为云的对象存储服务(Object Storage Service&#xff0c;OBS)是一个基于对象的海量存储服务&#xff0c;为客户提供海量、安全、高可靠、低成本的数据存储能力。 …

华为云云耀云服务器L实例评测|在Docker环境下部署Statping服务器监控工具

华为云云耀云服务器L实例评测&#xff5c;在Docker环境下部署Statping服务器监控工具 一、前言1.1 云耀云服务器L实例简介1.2 Statping简介1.3 Statping特点 二、本次实践介绍2.1 本次实践简介2.2 本次环境规划 三、购买云耀云服务器L实例3.1 购买云耀云服务器L实例3.3 查看云耀…