每日一博 - CAS(Compare-And-Swap)原理剖析

简介: 每日一博 - CAS(Compare-And-Swap)原理剖析

d0fdb2e70e1847b2b9749789048967d3.png

What’s CAS & sun.misc.Unsafe


全称 Compare-And-Swap , 主要实现的功能是和内存中的某个位置的值进行比较判断是否为预期值,如果是预期值则更改为新值, 整个过程具有原子性。



9b047aa44934416ba5414096d0d1e737.png


CAS & sun.misc.Unsafe


CAS属于CPU并发原语


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


在JDK中,主要体现在sun.misc.Unsafe类。

9eb7a6c8a71649c09a18f43f9b561b2a.png


当执行UnSafe类中的cas相关方法时, JVM会转换成类似汇编指令,通过它实现了原子操作。

来看个代码

package com.artisan.juc;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2021/11/6 13:11
 * @mark: show me the code , change the world
 */
public class CASTest {
    public static void main(String[] args) {
        // 设置初始值为100
        AtomicInteger atomicInteger = new AtomicInteger(100);
        // 使用atomicInteger的compareAndSet,如果为100,则更新为123
        boolean b = atomicInteger.compareAndSet(100, 123);
        System.out.println(b + "----" + atomicInteger.get());
        // 使用atomicInteger的compareAndSet,如果为100,则更新为456 (上一步已经更新成了123,所以不是100)
        b = atomicInteger.compareAndSet(100, 456);
        System.out.println(b + "----" + atomicInteger.get());
    }
}

c59038c92be04915a36746334093b944.png


输出

true----123
false----123



4412520df1c442d88a7646ed1f8208c0.png



以AtomicInteger为例底层原理剖析


继续在上个例子的基础上,完善一下,方便引入知识点,增加红框内如下代码:

6a90ff9047c44082bbb90ef8a9b569b5.png

输出

06f58b5a277f4786add60b5e9fb005ef.png


我们来分析下 getAndIncrement

先看看 AtomicInteger类


6c449b0a091547c9857a365f80b73bf7.png23d300c1c6ad43f6b6491964e96a9397.png


看方法的注释说明: 以原子的方式在当前值的基础上加1 ,返回的是加1之前的值。

可以看到其实是调用了unsafe# getAndAddInt

那先看看Unsafe类 呗



da56f03634f0484fa3cddf7b64585005.png


内部方法操作可以像C的指针一样直接操作内存


Unsafe位于sun.misc包中,该类的方法都是native的本地方法 ,这也意味着unsafe类中的方法都直接调用操作系统底层资源执行相应的任务。


Unsafe类是CAS的核心类. 我们知道Java无法直接访问底层操作系统,需要通过native方法来实现。 Unsafe这个魔法类可以理解为一个后门,通过该类可以直接操作特定的内存数据。


继续【getAndAddInt方法 】


d2f3d7a6f48849f4872281839ae573ac.png



07d493df19524528826551540b2c0076.png


b05fb42fdffd425dad4c337b292c9729.png


var1: AtomicInteger本对象


var2: 该对象值得引用地址


var4: 需要变动的数量


var5: var5 = this.getIntVolatile(var1, var2); 从主内存中拿到的值 , 如果当前值和期望值一样,就执行 var5 + var4 . (用var1和var2找到的内存中的真实值用该对象当前的值与var5比较)


do while 循环 , 如果compareAndSwapInt返回false,那么就一直执行 while方法,直到期望的值和真实值一样


a911f6e5685240dfb56f016643d83377.png

CAS有3个操作数,内存值V,旧的预期值,要修改的更新值。当且仅当预期值和内存值相同时,将内存值修改为更新值,否则不操作 .


CAS缺点


CAS不加锁,保证一致性,但是需要多次比较


对于多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候只能用锁来保证原子性


循环时间长,开销大(因为执行的是do while,如果比较不成功一直在循环,最差的情况,就是某个线程一直取到的值和预期值都不一样,这样就会无限循环)


只能保证一个共享变量的原子操作,当对一个共享变量执行操作时,我们可以通过循环CAS的方式来保证原子操作


ABA 问题


如果一个变量初次读取的时候是 A 值,它的值被改成了 B,后来又被改回为 A,那 CAS 操作就会误认为它从来没有被改变过。

相关文章
|
数据可视化 Go 数据库
性能分析神器:pprof命令详解与实战
性能分析神器:pprof命令详解与实战
1549 0
性能分析神器:pprof命令详解与实战
|
Prometheus 监控 Cloud Native
Prometheus PromQL语法
Prometheus PromQL语法
970 0
|
11月前
|
编解码 数据可视化 前端开发
如何使用 D3.js 创建一个交互式的地图可视化?
如何使用 D3.js 创建一个交互式的地图可视化?
|
存储 运维 数据挖掘
服务器数据恢复—修复xfs文件系统导致数据丢失的数据恢复案例
某公司一台服务器,连接了一台存储。该服务器安装linux操作系统,文件系统为xfs。 在运行过程中该服务器出现故障,管理员使用xfs_repair工具试图对xfs文件系统进行修复但失败,服务器中所有数据丢失。
|
弹性计算 关系型数据库 MySQL
阿里云数据库服务器价格表,数据库创建、连接和使用教程
阿里云数据库使用流程包括购买和管理。选择所需数据库类型如MySQL,完成实名认证后购买,配置CPU、内存和存储。确保数据库地域与ECS相同以允许内网连接。创建数据库和账号,设置权限。通过DMS登录数据库,使用账号密码连接。同一VPC内的ECS需添加至白名单以进行内网通信。参考官方文档进行详细操作。
503 3
|
人工智能
通义万象使用总结(1)
从获奖作品中学习精细的提示词和优化技巧,改进自己的作品,最终创造出满意的结果。
787 2
|
Java C语言
Java微信语音amr格式转mp3格式
Java微信语音amr格式转mp3格式
|
安全 数据安全/隐私保护
在非对称加密中,公钥和私钥的生成过程是如何进行的?
【5月更文挑战第13天】在非对称加密中,公钥和私钥的生成过程是如何进行的?
806 3
|
Web App开发 Python
Selenium Python 更改 chrome 默认下载目录
关于使用Selenium和Python无法更改Google Chrome默认下载目录的可能问题和解决方法,按照以上步骤,你应该能够成功使用Selenium和Python更改Google Chrome的默认下载目录。
584 0
|
存储 安全 数据安全/隐私保护
Harbor私有镜像仓库搭建
Harbor是由VMware开发的开源镜像仓库管理系统,具有以下一些主要特点和功能: 1.镜像管理 Harbor可以存储、管理镜像,支持访问控制、镜像复制、镜像删除等功能。 2.角色访问控制 可以创建用户和设置角色控制镜像的访问权限,例如只读或读写权限。 3.镜像复制 支持在多个Harbor实例之间复制镜像,保证分布式部署可以访问相同镜像。 4.镜像安全扫描 可以配置镜像安全扫描,检测镜像中的漏洞或风险。 5.镜像签名与信任 支持内容信任机制,确保镜像来源可信的同时保护镜像内容不被篡改。 6.策略管理 可以对用户访问、镜像复制和其他操作设置灵活的策略。
338 1