首页 > 编程语言 >JUC并发编程学习笔记(十八)深入理解CAS

JUC并发编程学习笔记(十八)深入理解CAS

时间:2023-11-10 09:22:55浏览次数:51  
标签:JUC CAS 编程 System atomicInteger int compareAndSet println

深入理解CAS

什么是CAS

为什么要学CAS:大厂你必须深入研究底层!有所突破!

java层面的cas------->compareAndSet

compareAndSet(int expectedValue, int newValue) 期望并更新,达到期望值就更新、否则就不更新!

package org.example.cas;

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        //JAVA CAS -> 比较并交换
        //期望、更新
        //compareAndSet(int expectedValue, int newValue)
        //如果我期望的值达到了那么就跟新、否则就不更新;CAS 是CPU的并发原语!
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        //达到期望值更新成功
        System.out.println(atomicInteger.get());
        //更新后未达到期望值,更新失败
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());
    }
}

Unsafe类

java不能直接操作内存,但是可以调用c++,c++可以操作内存,java可以通过native关键字定义的方法来调用c++。Unsafe类就像是java留给自己的一个后门。所以Unsafe类中都是native方法和调用native方法的方法!

在原子类里,有一个getAndIncrement方法用作自增、那么他的底层是如何实现的呢?

其实就是调用的unsafe类中的getAndAddInt方法

public final int getAndIncrement() {
    //dalta传入了1
    return U.getAndAddInt(this, VALUE, 1);
}
public final int getAndAddInt(Object o, long offset, int delta) {
    int v;
    do {
        //v每次都跟新为最新值,所以一直会是期望的值!就执行了++的操作
        v = getIntVolatile(o, offset);
        //如果当前对象o期望的值等于v,那么将当前对象o的值跟新为v+dalta;
    } while (!weakCompareAndSetInt(o, offset, v, v + delta));
    return v;
}
public final boolean weakCompareAndSetInt(Object o, long offset,
                                              int expected,
                                              int x) {
        return compareAndSetInt(o, offset, expected, x);
    }
public final native boolean compareAndSetInt(Object o, long offset,
                                                 int expected,
                                                 int x);

对比观察,其实getAndAddInt就是定义一个变量取到最新的值,然后通过while循环一直更新,其中getIntVolatile和compareAndSetInt都是通过java调用底层c++操作内存。

其中用到了一段标准的锁(自旋锁!):

 do {
        //v每次都跟新为最新值,所以一直会是期望的值!就执行了++的操作
        v = getIntVolatile(o, offset);
        //如果当前对象o期望的值等于v,那么将当前对象o的值跟新为v+dalta;
    } while (!weakCompareAndSetInt(o, offset, v, v + delta));

缺点

1、循环会耗时

2、一次性只能保证一个共享变量的原子性

3、会存在ABA问题

优点

自带原子性

CAS : ABA问题(狸猫换太子)!

package org.example.cas;

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        //JAVA CAS -> 比较并交换
        //期望、更新
        //compareAndSet(int expectedValue, int newValue)
        //如果我期望的值达到了那么就跟新、否则就不更新;   CAS 是CPU的并发原语!
        //===============捣乱的线程================
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.compareAndSet(2021, 2020));
        //达到期望值更新成功
        System.out.println(atomicInteger.get());
        //更新后未达到期望值,更新失败
        //===============期望的线程================
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());
        //getAndIncrement number++ 底层如何实现的?
        atomicInteger.getAndIncrement();//++方法

    }
}

标签:JUC,CAS,编程,System,atomicInteger,int,compareAndSet,println
From: https://www.cnblogs.com/nhgtx/p/17806042.html

相关文章

  • 卢卡斯定理/Lucas 定理
    卢卡斯定理/Lucas定理引入求\(C_{n+m}^n\modp\)。\(n,m,p\leq10^5\)。如果直接用阶乘求,可能在阶乘过程中出现了\(p\),而最后的结果没有出现\(p\),导致错误。有两种解决方法:1.求组合数时提前把\(p\)的质因子除掉。2.Lucas定理。所以Lucas定理用于处理模数较小且......
  • 08_模块化编程
    模块化编程将多位数码管显示不同数字的代码模块化模块化之前#include<REGX52.H>unsignedcharNixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x00};voidDelay(unsignedintxms) //@12.000MHz{ unsignedchardata......
  • (十二)C#编程基础复习——break、continue、goto:跳出循环
    在使用循环语句时,并不是必须等待循环完成后才能退出循环,我们也可以主动退出循环,C#为我们提供了break、continue和goto三种方式来跳出循环:1、break它不仅可以用来终止switch语句,在循环语句中使用时还可以用来跳出循环,执行循环外的下一条语句。如果是在嵌套循环中使用,例如在内层的......
  • (十一)C#编程基础复习——foreach循环
    除了前面介绍的几种循环语句外,C#同样也支持foreach循环,使用foreach可以遍历数组或者集合对象中的每一个元素。foreach会在每次循环的过程中,依次从数组或集合对象中取出一个新的元素放到foreach()里定义的变量中,直到所有元素都成功取出后退出循环。代码示例如下:int[]a=newin......
  • (十)C#编程基础复习——do while循环
    在C#中,dowhile循环同样可以多次迭代一部分程序,但它与我们前面学习的for循环和while循环不同,for循环和while循环会在循环开始之前先判断表达式的结果,只有表达式结果为真时才会开始循环,而dowhile循环会先执行一遍循环主体中的代码,然后再判断表达式的结果。也就是说,不论表达式的结......
  • 【Linux上机实验】新实验五 shell编程
    【前言】愿,所有相遇,都恰逢其时!愿,此刻心头,正满怀欣喜!---你好,朋友,欢迎你! ---对此篇博客中有任何问题和不懂的可以咨询QQ:27595909051.编写脚本,从键盘输入10个数,并计算这些数的和(用数组存放20个数)。1.输入visum.sh,创建一个名为"sum.sh"的文件......
  • 牛客[编程题] HJ29 字符串加解密
    HJ29 字符串加解密中等  通过率:25.47%  时间限制:1秒  空间限制:32M 描述对输入的字符串进行加解密,并输出。加密方法为:当内容是英文字母时则用该英文字母的后一个字母替换,同时字母变换大小写,如字母a时则替换为B;字母Z时则替换为a;当内容是数字时则把该数......
  • 为什么java被称作是平台无关的编程语言,举个详细的例子
     Java被称为平台无关的编程语言主要是因为它的设计哲学:“编写一次,到处运行”(WriteOnce,RunAnywhere-WORA)。这种特性是由Java的运行时环境(JavaRuntimeEnvironment,JRE)和Java虚拟机(JavaVirtualMachine,JVM)实现的。我将详细解释这一概念,并提供一个具体的例子来说明......
  • 牛客[编程题] HJ27 查找兄弟单词
    HJ27 查找兄弟单词  描述定义一个单词的“兄弟单词”为:交换该单词字母顺序(注:可以交换任意次),而不添加、删除、修改原有的字母就能生成的单词。兄弟单词要求和原来的单词不同。例如:ab和ba是兄弟单词。ab和ab则不是兄弟单词。现在给定你n个单词,另外再......
  • Java-Script 编程
    Java-Script编程目录Java-Script编程一.Js概念1.1简介1.2语法结构二.变量使用2.1定义变量2.2定义常量三.数据类型3.1数值类型(number)3.2字符类型(string)3.3.字符类型常用方法3.4布尔值(boolean)3.5null与undefined3.6数组3.7数组常用的方法3.8运算符四.流程......