CAS是什么?

比较并交换(compare and swap)是一条CPU并发原语

功能

判断内存中某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的,中间不予许中断,解决数据一致性问题。

底层原理

Unsafe类

是CAS的核心类,由于java无法直接访问底层系统,需要通过本地(native)方法访问,Unsafe相当于一个后门,该类可以直接操作特定的内存数据。 Unsafe类存在于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,因为java中的CAS依赖于Unsafe类中的方法

注意 Unsafe中的所有方法都是native修饰的,就是说Unsafe中的方法都是直接操作系统底层资源执行任务

底层汇编

底层代码

 // AtomicInteger类中方法:getAndIncrement,调用Unsafe类中的getAndAddInt  public final int getAndIncrement(){      return unsafe.getAndAddInt(this,valueOffset,1); } //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; }

解释:

  • var1是AtomicInteger对象本身

  • var2是对象值的引用地址

  • var4是需要变动的数值

  • var5是通过var1、var2找出的内存中的真实的值 方法:用对象的值和var5作比较,如果相同,则更新var5+var4并且返回TRUE,如果不同则继续取值然后再比较,直到更新完成

缺点

1、 循环时间开销大

2、只能保证一个共享变量的原子操作

3、 引出ABA问题

ABA问题

CAS算法实现一个重要前提需要提取出内存中某时刻的数据并在当下时刻比较并替换,那么在这个时间差内会导致数据的变化。

举例:

一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且线程two进行了一些操作将A变成了B,然后又将V位置的数据变成了A,而这时候线程one进行 CAS操作的时候发现内存中仍然是A,然后one线程提示操作成功。

尽管one线程的CAS操作成功,但是不代表这个线程是没问题的

 

代码还原

package com.dayu.inter;import sun.rmi.runtime.NewThreadAction;import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;/*** @Author: dayu* @Date: 2019/9/24 15:13* @Description*/
public class ABADemo {public static void main(String[] args) {System.out.println("=========下面是ABA问题的产生==========");AtomicReference<Integer> atomicReference = new AtomicReference<>(100);new Thread(() -> {System.out.println(atomicReference.compareAndSet(100, 101)+"\t"+atomicReference.get());System.out.println(atomicReference.compareAndSet(101, 100)+"\t"+atomicReference.get());}, "t1").start();new Thread(() -> {//休息一会,让线程t1先执行一遍ABA的问题try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(atomicReference.compareAndSet(100, 2000)+"\t"+atomicReference.get());}, "t2").start();//休息一会,确保上面两个线程执行完毕try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("=========下面是ABA问题的解决==========");//有点类似于乐观锁//初始值设定100,时间戳(版本号=1)AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);new Thread(() -> {int stamp = atomicStampedReference.getStamp();System.out.println(Thread.currentThread().getName()+"\t 第一次获取版本号"+stamp);//休息一会,等待t4获取版本号try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}atomicStampedReference.compareAndSet(100,101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);System.out.println(Thread.currentThread().getName()+"\t 第2次获取版本号"+atomicStampedReference.getStamp());atomicStampedReference.compareAndSet(101,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);System.out.println(Thread.currentThread().getName()+"\t 第3次获取版本号"+atomicStampedReference.getStamp());}, "t3").start();//t4和t3最初获取到的版本号一致,new Thread(() -> {int stamp = atomicStampedReference.getStamp();System.out.println(Thread.currentThread().getName()+"\t 第一次获取版本号"+stamp);//休息一会,确保t3完成一次ABAtry {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}boolean result = atomicStampedReference.compareAndSet(100, 2019, stamp, stamp + 1);System.out.println(Thread.currentThread().getName()+"\t 是否修改成功:"+result+"\t 当前真实的版本号:"+atomicStampedReference.getStamp()+"\t 当前真实的值:"+atomicStampedReference.getReference());}, "t4").start();}
}

为了解决ABA问题,在原子引用类上加上版本号,这个有点类似于mysql的乐观锁一样,每个线程更改一次都需要更改版本号,那么多线程同时获取到同一个版本号的时候也只有一个线程可以更改成功。

转载于:https://www.cnblogs.com/dayu007/p/11578871.html

CAS是什么?ABA问题的产生和解决方法相关推荐

  1. 真实业务场景展现CAS原理的ABA问题及解决方案

    文章目录 阅读提示 CAS原理.ABA问题介绍 真实业务场景 如何解决ABA问题 CAS学习总结 阅读提示 本文将借助开保险柜的业务场景重点阐述误用AtomicBoolean引起的ABA问题,以及解决 ...

  2. Java并发基石CAS原理以及ABA问题

    在学习CAS之前,先从一个简单的案例入手,进而引出CAS的基本使用: 1.基于CAS的网站计数器 需求: 我们开发一个网站,需要对访问量进行统计,用户每发送一次请求,访问量+1,如何实现? 我们模拟有 ...

  3. Java多线程之常见锁策略与CAS中的ABA问题

    ⭐️前面的话⭐️ 本篇文章将介绍常见的锁策略以及CAS中的ABA问题,前面介绍使用synchronized关键字来保证线程的安全性,本质上就是对对象进行加锁操作,synchronized所加的锁到底是 ...

  4. aba问题mysql_解决CAS机制中ABA问题的AtomicStampedReference详解

    AtomicStampedReference是一个带有时间戳的对象引用,能很好的解决CAS机制中的ABA问题,这篇文章将通过案例对其介绍分析. 一.ABA问题 ABA问题是CAS机制中出现的一个问题, ...

  5. Handle table中CAS操作与A-B-A Problem解析

    在研究handle table的时候顺便研究的东西.Baidu了下,发现国内这方面的资料几乎没得,然后就准备瞎bb下,为下面的一篇介绍handle table的结构做准备. 关于lock-free d ...

  6. 高并发之CAS机制和ABA问题

    什么是CAS机制 CAS是英文单词Compare and Swap的缩写,翻译过来就是比较并替换 CAS机制中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B. 看如下几个例子: pac ...

  7. 【Java 并发编程】线程锁机制 ( 悲观锁 | 乐观锁 | CAS 三大问题 | ABA 问题 | 循环时间长问题 | 多个共享变量原子性问题 )

    文章目录 一.悲观锁 二.乐观锁 三.乐观锁 CAS 三大问题 一.悲观锁 假设有 222 个线程 , 线程 A 和 线程 B ; 线程 A 访问共享资源 , 线程 B 等待 , 一旦线程 A 访问结 ...

  8. cas引出的ABA问题?如何解决?- 理解原子引用、时间戳(版本号)原子引用

    ABA问题: 假如有两个线程1,2: cas下:1.线程取值完等待,2线程取值并把A改成B,有把B改成A,这是1线程执行会任务A还是原来的A没有发生改变,如果不在乎中间结果,只看收尾,那么没必要解决A ...

  9. tcp out of order解决_Java解决CAS机制中ABA问题的方案

    通过对atomic包的分析我们知道了CAS机制,我们在看一下CAS的公式. CAS(V,A,B)1:V表示内存中的地址2:A表示预期值3:B表示要修改的新值 CAS的原理就是预期值A与内存中的值相比较 ...

最新文章

  1. Science Bulletin:上海植生所王二涛组发表基于绝对丰度的植物根际微生物群落“扩增-选择”组装模型
  2. python基础练习(十)
  3. innerHTML和value的区别
  4. 台式计算机技术方案,2017年4月自考02316计算机应用技术真题及答案
  5. 从其他电脑拷mysql到自己电脑_mysql 数据库复制到其他电脑
  6. 计算机二级考试考不考二进制,如何通过计算机一、二级考试?方法很重要,过来人的经验告诉你...
  7. cortex m4 中文手册_奥迪RS4 Avant都来了,新一代宝马M4还会远吗?
  8. display:none的进一步理解
  9. 增强SEO的div+css命名规则
  10. 这款国产神器,我爱了
  11. appleId登录java
  12. mysql grant 用户权限总结
  13. 迈卡名车茂深度访谈信达名车——宋丙刚:自信坚韧 坚持不懈
  14. 编程实战(2)——Python解微分方程方法总结
  15. html制作图片动画效果代码,HTML5 Canvas:制作动画特效
  16. Doxygen 使用总结
  17. 我肝了long long time 的笔记(别白嫖啊)
  18. BERT6mA:使用基于深度学习的方法预测DNA N6甲基腺嘌呤位点
  19. selenium之DDT:使用DDT模块实现数据驱动测试
  20. RTOS 系统篇-看门狗 WatchDog[不喂狗就咬你]

热门文章

  1. aws-ec2-双网卡问题
  2. JSR-303 Bean Validation 介绍及 Spring MVC 服务端验证最佳实践
  3. jQuery中的动画
  4. 机会的度量:概率和分布
  5. ZW网络团队及资源简介
  6. 编译原理-First集和Follow集
  7. 撩课-Java每天5道面试题第11天
  8. MAVEN项目环境搭建
  9. sql的nvl()函数
  10. Spring data jpa命名规范