CAS算法实现

article/2025/8/30 2:57:47

https://blog.csdn.net/bluetjs/article/details/52261490?locationNum=15&fps=1

1.什么是cas?

    cas是一种无锁算法(非阻塞算法:一个线程的失败或者挂起不应该影响其他线程的失败或者),是compare and swap的缩写,表示为比较并交换的意思

2.cas算法:

    cas有三个操作数,v内存值,旧的预算值A,需要修改的值B,当且预期值A和内存值V相等时,将内存值修改为B,否则什么都不做、

3.++i操作

    

public final int incrementAndGet() {

    for (;;) {

        int current = get();

        int next = current + 1;

        if (compareAndSet(current, next))

            return next;

    }

}

这里采用了CAS操作,每次从中读取数据都会将此数据和+1后的结果进行CAS操作,如果成功则返回结果否则重试到成功为止,而这里的compareAndSet利用JNT( JNI:Java Native Interface为JAVA本地调用,允许java调用其他语言。完成CPU的指令操作

compareAndSet的代码

public final boolean compareAndSet(int expect, int update) {   

    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);

    }

compareAndSwapInt类似这样的逻辑:

if(this==except){

    this=update

    return true;

}else{

    return false;

}

4.CAS原理:

    CAS是通过调用JNT代码实现的,而compareAndSwapInt就是就是借用CAS来调用CPU底层指令实现的下面通过(inel x86)来解释CAS的实现原理

public final boolean compareAndSet(int expect, int update) {   

    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);

    }

可以看到这是个本地方法调用。这个本地方法在openjdk中依次调用的c++代码为:unsafe.cpp,atomic.cpp和atomicwindowsx86.inline.hpp。这个本地方法的最终实现在openjdk的如下位置:openjdk-7-fcs-src-b147-27jun2011\openjdk\hotspot\src\oscpu\windowsx86\vm\ atomicwindowsx86.inline.hpp(对应于windows操作系统,X86处理器)。下面是对应于intel x86处理器的源代码的片段:

 

// Adding a lock prefix to an instruction on MP machine

// VC++ doesn't like the lock prefix to be on a single line

// so we can't insert a label after the lock prefix.

// By emitting a lock prefix, we can define a label after it.

#define LOCK_IF_MP(mp) __asm cmp mp, 0 \

__asm je L0 \

__asm _emit 0xF0 \

__asm L0:

 

 

inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {

// alternative for InterlockedCompareExchange

int mp = os::is_MP();

__asm {

mov edx, dest

mov ecx, exchange_value

mov eax, compare_value

LOCK_IF_MP(mp)

cmpxchg dword ptr [edx], ecx

}

}

 

如上面源代码所示,程序会根据当前处理器的类型来决定是否为cmpxchg指令添加lock前缀。如果程序是在多处理器上运行,就为cmpxchg指令加上lock前缀(lock cmpxchg)。反之,如果程序是在单处理器上运行,就省略lock前缀(单处理器自身会维护单处理器内的顺序一致性,不需要lock前缀提供的内存屏障效果)。

 

5.CAS的缺点:

    CAS虽然能高效的保证原子操作,但CAS还是存在三大问题,ABA问题,循环时间长开销大,只能保证一个共享变量的原子操作

    1.ABA问题因为CAS需要在操作时检查值有没有发生变化,,如果没有发生变化就更新,但是如果一个值原来是A变成了B,再变成A,那么CAS检查不到他的值发生变化,而实际上是变化了的,A->B->A,也就是说,CAS不能发现数值是否改变的过程,他只会看到结果,

    问题实例化:假如银行扣费,有两个线程操作,正确应该是一个扣费成功,一个失败,而我应少50元,假如第一个线程扣费50元后,第二个线程检查之前,我收到转账50元,那么线程2还会对我进行扣费,所以我被扣100元

    解决方法:添加版本号,1A->2B->3A

    2.循环时间长:开销大:如果CAS长时间不成功,则会带来非常大的开销,如果,jvm支持pause指令,效率会有一定的提升,pause指令有两个作用,1、延迟流水线执行指令,使cpu不会消耗过多执行资源2、避免退出循环的时候因内存顺序冲突而引起cpu流水线被清空,从提高CPU的执行效率

    3.只能保证一个共享变量的原子操作:当对一个共享变量执行操作时,我们可以使用循环的方式来保证操作的原子性,这时候就要用锁

6.CAS的优化

    java8对CAS的优化:为了防止CAS不断自旋,消耗大量资源,于是java8推出了一个LongAdder,他使用分段CAS自动分段迁移的方式来大幅度提升多线程高并发执行CAS操作0性

https://mp.weixin.qq.com/s?src=11×tamp=1563419615&ver=1735&signature=R8p-4Q7AnqkeEaViijsaymppXy-O34bCEQO9GHt-Tw*V3me0lVHkfN92reDkOks-94na9RUIuiKqarUUJhdK6SjkjuU1HgGDT34ots1-T7Fs*xO1ywUWW6jOjokZt-eK&new=1

        在LongAdder的底层实现中,首先有一个base值,刚开始多线程不停地累加数值,都是对base进行累加的,比如刚开始累加成base=5;接着,如果发现并发更新的线程数过多,就开始实行分CAS机制也就是内部会创建一个Cell数组,没个数组是一个分段值,它内部也实现了自动分段迁移的机制,就是如果一个Cell的value执行CAS失败了,那么他就会自动寻找另外一个Cell分段内的value值进操作

     优点是把CAS的计算压力分散到不同的Cell中了,解决了线程空自旋、自旋不等待CAS操作的问题,让一个CAS来执行时可能尽快的完成这个操作

 

 

 


http://chatgpt.dhexx.cn/article/jI9eG7Yt.shtml

相关文章

修改Idea的jdk版本

概述 idea很多地方都设置了jdk版本,不同模块的jdk版本也可能不一样,下面整理下涉及jdk或者jre版本的几个地方。 方法一 File - Settings - Build, Execution, Deployment - Build Tools - Maven - Importing 方法二 File - Settings - Build, Exec…

Linux切换jdk版本

开发常识 命令行输入下列命令,然后输入 1 、2、3 选择你想要的 jdk 版本: sudo update-alternatives --config java选择完之后查看 jdk 版本: java -version

如何查看JDK版本信息

如何查看JDK版本号 一、前言二、 Windows的dos窗口 一、前言 在下载某些工具时需要知道自己电脑安装的JDK版本号,这里介绍了一种可以看自己JDK版本号的方法。 二、 Windows的dos窗口 1.电脑WindowsR键,打开命令行窗口   2.在命令行里面输入cmd;   3…

mac安装多个JDK版本

因对不同版本的JDK需求,有时候需要安装多个切换使用,这里我为Mac安装了多个JDK。在已有JDK8的基础上又安装了JDK11。 1、国内镜像下载JDK11,下载地址:https://repo.huaweicloud.com/java/jdk/11.0.29/jdk-11.0.2_osx-x64_bin.dmg…

更改JDK版本

1、更改环境变量:JAVA_HOME的路径(此路径下要有bin目录) 换成你要用的java的版本所在的路径 2、找到系统变量path下的java路径,将此路径下的三个文件全部删掉 3、打开regedit 修改数据数值即可,如下图切换成功

查看javajdk版本

查看当前电脑的Java/JDK版本的方法 1.winR 打开运行窗口,输入 cmd 2.在控制台中输入java --version或者java -version,即可查看Java版本号 Java所有版本 版本号 发布日期 JDK Version 1.0 1996-01-23 Oak(橡树) JDK Version 1.1 1997-02-19 …

如何更换jdk版本

如何更换jdk版本 因为很多时候需要切换jdk版本。也是走了很多弯路才弄好。此次演示的是将1.7 的版本更换成1.8 的。下面是详细步骤先查看当前版本,输入cmd 打开命令提示符后输入 java -version 即可 可以将1.8 的jdk 于1.7 的jdk 安装在同一个目录下,会…

linux 安装多版本jdk

1、先要安装多个版本的jdk,可以从官网进行下载,然后解压到你需要的目录 例如:/home/xxx/Documents/jdk8 /home/xxx/Documents/jdk17 2、先执行软连接设置,将jdk所在的真实路径建立连接 #数字越大默认级别越高sudo updat…

IDEA 切换 JDK 版本

IDEA 中一个项目切换不同的 JDK 版本 File -> Project Structure -> Project -> SDK: IDEA 一个 Project 内,多个 Module 间使用不同的 JDK 问题描述 项目结构如下: 想要在这样一个 Project 中的多个 Module 之间使用不同的 J…

查看 jdk 版本及安装路径

1、查看电脑的 jdk 版本 (1)键盘 win R 打开 “运行” ,输入 cmd 回车,打开命令窗口 (2)输入 java -version 查看安装的 jdk 版本 2、查看 jdk 的安装路径 (1)在命令窗口输入 jav…

安装多个jdk版本并切换

官网下载:Java Downloads | Oracle 我们在学习的过程中 经常用到不同的jdk版本 那么如何在一台电脑上同时安装2个jdk版本 并进行切换呢? 我这里面以jdk1.8 和jdk17为例 我已经成功安装2个jdk 一. 查看安装的jdk版本 二 配置 1.配置JAVA_HOME 在系…

更换JDK版本

1.配置环境变量 更换CLASS_PATH指向目录,更换JAVA_HOME指向目录 更换PATH变量中的参数,将jdk与jre指向更换掉 控制台输入java -version 可以观测到版本是否变更 2.IDEA更换jdk配置 需要在idea中选择file--project structure如下图操作更换相关配置 在file--settings中进行下图…

ubuntu切换JDK版本

因为JKD版本的影响,我的ecplise打不开,所以可以采用这种方法切换不同的JDK版本。 首先查看JDK版本: java -version如: 一、安装jdk 我要切换成另外一个版本。如果没有但是有需要的话,可以先安装另外一个版本&#…

安装多个jdk版本

初衷 在安装jdk的过程中由于要和老师教授的jdk版本一致,又不忍心卸载原来的jdk版本。因此想想能不能在一台电脑上安装多个jdk版本,然后无缝切换。在这里记录一下一些步骤与碰到的坑。 期间也查阅了许多博客,在此感谢各位博主。 一. 步骤 1…

宝塔升级JDK版本

宝塔面板 JDK8 → JDK17 一、下载 JDK17 打开服务器命令行,创建并进入/usr/lib/jvm/ 目录: mkdir -p /usr/lib/jvm cd /usr/lib/jvmwget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz二、解压 JDK 安装包并重命名 tar -…

Intellij IDEA--修改JDK版本

原文网址:Intellij IDEA--修改JDK版本_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Idea如何修改JDK的版本。 第1步:配置JDK环境变量 装好JDK之后,要添加一个环境变量:JAVA_HOME: 第2步:修改Idea配置 由Ma…

新版本jdk(9、11、12、13、14)特性

目录 背景 jdk9新特性 目录结构的改变 模块化系统 要解决的问题 概念 实现目标 示例 jShell命令 多版本兼容jar包 接口中的私有方法 钻石操作符(泛型)的升级 try语句的升级 下划线命名标识符的限制 String存储结构的变化 快速创建只读集合 增强的流api takeWhi…

知识小笔记

1. 什么是JDK? JDK有三个版本,分别是: (1)J2SE: 标准版,主要用于开发桌面应用程序。 (2)J2EE: 企业版,主要用于开发企业及应用程序,如电子商务网站,ERP系统…

JDK的版本

JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK)。 SE(JavaSE),standard edition,标准版,是我们通常用的一个版本,从JDK 5.0开始,改名为Java SE。 EE(JavaEE),enterprise edition&#xff0c…

jdk的版本号解惑

做Java开发的时候,经常看到这些所谓的“同义词”,Java8、JDK8、JDK1.8、J2SE8、J2SE1.8,他们之间的区别和关系如下所示, (1) Java与JDK的区别与关系 这个应该是看问题的角度不同,在用户眼中,Java是Java应…