CAS

全称是CompareAndSwap,它是一条CPU并发原语。用来判断内存某个位置的值是否为预期值,如果是则改为更新的值,这个过程是原子的。AtomicInteger之所以能保证原子性是依赖于UnSafe类,这个类是Java最底层的类之一,里面都是很屌的native方法,都是其他语言写的,咱看不见,Unsafe类可以执行以下几种操作:

  • 分配内存,释放内存
  • 可以定位对象的属性在内存中的位置,可以修改对象的属性值。使用objectFieldOffset方法
  • 挂起和恢复线程,被封装在LockSupport类中供使用
  • CAS
相关源码
 public final class Unsafe {//源码确实美如画public final int getAndAddInt(Object var1, long var2, int var4) {int var5;do {var5 = this.getIntVolatile(var1, var2);} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));return var5;}
}
public class AtomicInteger extends Number implements java.io.Serializable {private static final long serialVersionUID = 6214790243416807050L;// setup to use Unsafe.compareAndSwapInt for updatesprivate static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {//这个玩意是内存偏移量valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile int value;/*** Atomically increments by one the current value.** @return the previous value*/public final int getAndIncrement() {//this指的是这个对象本身return unsafe.getAndAddInt(this, valueOffset, 1);}
}

CAS的缺点

  • 如果循环时间长,CPU开销很大
  • 只能保证一个共享变量的原子操作,对于多个共享变量操作时,循环CAS无法保证操作的原子性,这时候只能使用锁来保证
  • 会有ABA问题
ABA

CAS算法是取出内存中某时刻的数据并在当下时刻比较并替换,这中间会有一个时间差导致数据变化。比如说有两个线程,一快一慢,同时从主内存中取变量A,快线程将变量改为B并写入主内存,然后又将B从主内存中取出再改为A写入主内存,这时候慢线程刚完成了工作,使用CAS算法,发现预期值还是A,然后慢线程将自己的结果写入主内存。虽然慢线程操作成功,但是这个过程可能是有问题的

原子引用

AtomicReference用来把特定对象编程原子类,AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,底层采用的是compareAndSwapInt实现CAS,比较的是数值是否相等,而AtomicReference则对应普通的对象引用,底层使用的是compareAndSwapObject实现CAS,比较的是两个对象的地址是否相等,也就是它可以保证你在修改对象引用时的线程安全性。

原子引用时间戳

对于ABA问题可以在比较值的同时加上版本号,或者说是时间戳。AtomicStampedReference
这个类在创建的时候要求指定一个初始的版本号,并且每次做CAS操作的时候要求对比版本号,且版本号需要自增

   /*** Creates a new {@code AtomicStampedReference} with the given* initial values.** @param initialRef the initial reference* @param initialStamp the initial stamp*/public AtomicStampedReference(V initialRef, int initialStamp) {pair = Pair.of(initialRef, initialStamp);}
/*** Atomically sets the value of both the reference and stamp* to the given update values if the* current reference is {@code ==} to the expected reference* and the current stamp is equal to the expected stamp.** @param expectedReference the expected value of the reference* @param newReference the new value for the reference* @param expectedStamp the expected value of the stamp* @param newStamp the new value for the stamp* @return {@code true} if successful*/public boolean compareAndSet(V   expectedReference,V   newReference,int expectedStamp,int newStamp) {Pair<V> current = pair;returnexpectedReference == current.reference &&expectedStamp == current.stamp &&((newReference == current.reference &&newStamp == current.stamp) ||casPair(current, Pair.of(newReference, newStamp)));}

Atomic类如何保证原子性相关推荐

  1. setnx是原子操作吗_谈谈Volatile关键字?为什么不能保证原子性?用什么可以替代?为什么?...

    大家好,欢迎关注我的公众号码猿bug,需要资料的话可以加我微信好友. 再谈volatile关键字之前,首先必须聊聊JMM内存模型! JMM主要的特性:可见性.原子性,顺序性 Java 虚拟机规范试图定 ...

  2. volatile不能保证原子性,atomic不仅保证可见性还有原子性CAS分析

    给一个变量加了volatile关键字,就会告诉编译器和JVM的内存模型:这个变量是对所有线程共享的.可见的,每次jvm都会读取最新写入的值并使其最新值在所有CPU可见.volatile似乎是有时候可以 ...

  3. 15.unsafe类的CAS是怎么保证原子性的?

    老王:小陈啊,上一章我们讲了usafe是个啥东西,以及unsafe提供的几大类的功能 老王:这一章啊,我们要花个时间专门讲unsafe提供的cas功能,这个cas的功能是我们后面将Atomic原子类体 ...

  4. 为什么volatile不能保证原子性而Atomic可以?

    在上篇<非阻塞同步算法与CAS(Compare and Swap)无锁算法>中讲到在Java中long赋值不是原子操作,因为先写32位,再写后32位,分两步操作,而AtomicLong赋值 ...

  5. java volatile 原子性_为什么volatile不能保证原子性而Atomic可以?

    在上篇<非阻塞同步算法与CAS(Compare and Swap)无锁算法>中讲到在Java中long赋值不是原子操作,因为先写32位,再写后32位,分两步操作,而AtomicLong赋值 ...

  6. java中的Atomic类

    文章目录 问题背景 Lock 使用Atomic java中的Atomic类 问题背景 在多线程环境中,我们最常遇到的问题就是变量的值进行同步.因为变量需要在多线程中进行共享,所以我们必须需要采用一定的 ...

  7. 18.AtomicReference、AtomicStampReference底层原理。多个变量更新怎么保证原子性?CAS的ABA问题怎么解决?

    老王:小陈啊,上一章我们说了AtomicInteger.AtomicBoolean的底层原理,这一篇我们就来说说Atomic系列的另一个分类AtomicReference和AtomicStampRef ...

  8. 两个原子操作组合到一块不一定是能保证原子性

    1.两个原子操作组合到一块不一定是能保证原子性 ConcurrentLinkedQueue AtomicInteger  两个类都为线程安全的类,但是组合起来并不能保证原子性: public stat ...

  9. volatile学习(可见性,不保证原子性,禁止指令重排(双端检索机制))

    volatile是java虚拟机提供的轻量级的同步机制: 1.保证可见性:线程之间可见性(及时通知) 2.不保证原子性 3.禁止指令重排 先了解一下jvm同步 由于JVM运行程序的实体是线程,而每个线 ...

最新文章

  1. opencv 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突
  2. 网络层:IP协议详解(IP协议真的得看这篇)
  3. C/C++ 中判断某一文件或目录是否存在
  4. 解决ajax重复提交问题?
  5. PyTorch入门(三)--实现简单图像分类器
  6. 第一次用PHP做电影站 用thinkphp开发的!!
  7. ❤️《分布式 Dubbo+Zookenper+SpringBoot》(建议收藏)❤️
  8. 如何查询硬盘序列号,百度的答案全是错的
  9. duilib 添加自定义list一例
  10. php网上花店管理系统的论文,网上花店管理系统
  11. 计算机电子表格的优点,信息技术《电子表格的特点及应用》的说课稿
  12. C#字节数组与字符串相互转换代码案例
  13. java毕业设计房产交易系统Mybatis+系统+数据库+调试部署
  14. DNS:快速搭建公司内网DNS解析服务器
  15. python 判断是否是元音字母
  16. 吴军老师《给中学生/大学生的书单》----Yohao整理
  17. spring-boot 2.5.6 问题:WARN: This connection is using TLSv1.1
  18. Java教程,Java视频,培训机构免费资源下载汇总帖,全网最有情怀,集合所以品牌机构(持续更新...)
  19. C++在线编辑器:cpp.sh
  20. vue 前端生成二维码,并转换为图片

热门文章

  1. Mac下嵌入式开发初步(二)
  2. dw常用标签_dreamweaver中常用到的标签及含义
  3. SQL Server健康检查的重要性
  4. win10去掉快捷方式小箭头_电脑一分钟小技巧:桌面快捷方式小箭头去除与恢复方法...
  5. 计算机视觉(视频追踪检测分类、监控追踪)常用测试数据集
  6. IDEA小技巧之痛苦面具 主菜单不见了怎么办?
  7. Flask_从入门到放弃?不!!!从入门到入土!!
  8. Swift之函数的语法和使用 | CSDN创作打卡
  9. 【Linux】Linux 开放端口
  10. c语言作业订单号查询,C语言 查询订单系统进不去 还请高手指点