JUC并发编程学习笔记(十八)深入理解CAS
1.JUC并发编程学习笔记(二)Lock锁(重点)2.JUC并发编程学习笔记(一)认知进程和线程3.JUC并发编程学习笔记(三)生产者和消费者问题4.JUC并发编程学习笔记(四)8锁现象5.JUC并发编程学习(五)集合类不安全6.JUC并发编程学习笔记(六)Callable(简单)7.JUC并发编程学习笔记(七)常用的辅助类8.JUC并发编程学习笔记(八)读写锁9.JUC并发编程学习笔记(九)阻塞队列10.JUC并发编程学习笔记(十)线程池(重点)11.JUC并发编程学习(十一)四大函数式接口(必备)12.JUC并发编程学习笔记(十二)Stream流式计算13.JUC并发编程学习(十三)ForkJoin14.JUC并发编程学习笔记(十四)异步回调15.JUC并发编程学习笔记(十五)JMM16.JUC并发编程学习笔记(十七)彻底玩转单例模式17.JUC并发编程学习笔记(十九)原子引用18.JUC并发编程(终章)各种锁的理解19.JUC并发编程学习笔记(十六)Volatile
20.JUC并发编程学习笔记(十八)深入理解CAS
深入理解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();//++方法 } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构