Java多线程之CAS深入解析


目录:

  1. CAS是什么
  2. CAS底层原理Unsafe深入解析
  3. CAS缺点

引子:蚂蚁花呗一面:讲一讲AtomicInteger,为什么要用CAS而不是synchronized?

1. CAS是什么


  1. CAS的全称为Compare-And-Swap,它是一条CPU并发原语。

  2. 它的功能是判断内存某个位置的值是否为期望值,如果是则更改为新的值,这个过程是原子的。

  3. CAS并发原语体现在JAVA语言中就是sun.misc.Unsafe类中的CAS方法,JVM会帮我们实现CAS汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原语属于操作系统用语范畴范,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就说CAS是一条CPU的原了指令,不会造成所谓的数据不一致问题。


简单测试代码:

public class CASDemo {public static void main(String[] args) {AtomicInteger atomicInteger = new AtomicInteger(5);// main do thingSystem.out.println(atomicInteger.compareAndSet(5, 6)+"current data:"+atomicInteger.get());System.out.println(atomicInteger.compareAndSet(5, 2019)+"current data:"+atomicInteger.get());}
}

编译结果:


2. CAS底层原理Unsafe深入解析


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

  2. 注意Unsafe类中的所有方法都是native修饰的,也就是Unsafe类中的方法都直接调用操作系统底层资源执行相应任务。

  3. 原子整型在i++中操作多线程环境下不需要加synchronized,也能保证线程安全,是因为它用的是Unsafe类,源代码如下:

  4. 源码解析,图如下

    解析:getAndAddInt()方法底层调用的是unsafe,传三个参数,当前对象,内存地址偏移量,增量1,底层调用的是CAS思想,如果比较成功+1,失败再重新获得比较一次,直至成功为止。


假设线程A和线程B两个线程同时执行getAndAddInt操作(分别跑在不同CPU上):

  1. Atomiclnteger里面的value原始值为3,即主内存中Atomiclnteger的value为3,根据JMM模型,线程A和线程B各自持有一份值为3的value的副本分别到各自的工作内存。

  2. 线程A通过getIntVolatile(var1,var2)拿到value值3,这时线程A被挂起。

  3. 线程B也通过getIntVolatile(var1,var2)方法获取到value值3,此时刚好线程B没有被挂起并执行compareAndSwaplnt方法
    比较内存值也为3,成功修改内存值为4,线程B打完收工,一切OK

  4. 这时线程A恢复,执行compareAndSwaplnt方法比较,发现自己手里的值数字3和主内存的值数字4不一致,说明该值己
    经被其它线程抢先一步修改过了,那A线程本次修改失,只能重新读取重新来一遍了。

  5. 线程A重新获取value值,因为变量value被volatile修饰,所以其它线程对它的修改,线程A总是能够看到,线程A继续执
    行compareAndSwaplnt进行比较替换,直到成功。


  1. Unsafe底层汇编

3. CAS缺点

篇幅原因,新开了一个博客文章进行解析,请看:

Java基础之CAS缺点

Java多线程之CAS深入解析相关推荐

  1. Java多线程之CAS缺点

    Java多线程之CAS缺点 目录: 循环时间开销很大 只能保证一个共享变量的原子操作 引来ABA问题及解决方案(重点) 1. 循环时间开销很大 通过看源码,我们发现有个do while,如果CAS失败 ...

  2. Java多线程之8Lock问题解析

    Java多线程之8Lock问题解析 本文目录 1. 8Lock实例: 标准访问的时候,请问先打印邮件还是短信? sendEmail方法暂停4秒钟,请问先打印邮件还是短信? 新增Hello普通方法,请问 ...

  3. java中多线程之CAS(compareAndSet),Unsafe类大白话详解.

    java中多线程之CAS(compareAndSet),Unsafe类大白话详解 什么是CAS CAS原理 Unsafe类:     什么是CAS 比较并交换 在学习CAS之前,我们先了解一下JMM. ...

  4. JAVA多线程之wait/notify

    本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...

  5. Java多线程之Callable、Future和FutureTask

    Java多线程之Callable接口 自己想总结一下的,看到一篇总结的更好的博客,就转载了,突然感觉真轻松,哈哈哈哈 文章转载于:Matrix海子:Java并发编程:Callable.Future和F ...

  6. Java多线程之Synchronized和Lock的区别

    Java多线程之Synchronized和Lock的区别 目录: 原始构成 使用方法 等待是否可以中断 加锁是否公平 锁绑定多个条件Condition 小结:Lock相比较Synchronized的优 ...

  7. Java多线程之volatile详解

    Java多线程之volatile详解 目录: 什么是volatile? JMM内存模型之可见性 volatile三大特性之一:保证可见性 volatile三大特性之二:不保证原子性 volatile三 ...

  8. Java多线程之Semaphore用法

    Java多线程之Semaphore用法 本文目录: Semaphore基本概念 Semaphore使用案例:3个停车位,6辆车去抢,走一辆,抢一个停车位. 1. Semaphore基本概念 在信号量上 ...

  9. Java多线程之CyclicBarrier用法

    Java多线程之CyclicBarrier用法 本文目录 CyclicBarrier的基本概念 CyclicBarrier的案例:集齐7颗龙珠就可以召唤神龙 1. CyclicBarrier的基本概念 ...

最新文章

  1. 利用OpenCv读取一张图片并显示
  2. Windows 技术篇-利用telnet方法ping端口通不通实例演示,如何测试服务器端口是否启用,windows启用telnet功能
  3. 文件加密问题(中文字符)
  4. python如何调用java写的接口_Python 调用翻译接口
  5. 字符,字符串,int之间互相转换
  6. java获取vm运行参数_如何获取在Java中运行Java VM的版本?
  7. 女孩子适合学习前端开发吗?
  8. Java实现打印进度条
  9. vue如何区别浏览器刷新和关闭
  10. mysql cnf和ini区别_再谈mysql的配置文件my.ini or my.cnf (之一) .
  11. 寂静岭3java攻略_《寂静岭3》完整流程攻略
  12. 孤荷凌寒自学python第七十九天开始写Python的第一个爬虫9并使用pydocx模块将结果写入word文档...
  13. 2023软考考哪个证书好?
  14. Understanding C/C++ Strict Aliasing
  15. Python——使用OGR操作矢量数据
  16. linux debian怎么重启网卡,debian10网卡设置
  17. 当机器有了“视力”,它会抢人类的饭碗并取代人类吗?
  18. 计算2000年1月1日到2020年1月1日相距多少天 java
  19. 用ftp在个人电脑和服务器之间进行文件传输
  20. Leetcode 1488. Avoid Flood in The City(python)

热门文章

  1. JAVA学习笔记(8)
  2. jvm类加载器以及双亲委派
  3. sql 存储过程中top 后面跟参数的问题
  4. 几个免费高质量图标搜索引擎。
  5. 向模态窗体传递参数和获取返回值
  6. POJ - 1966 Cable TV Network(最小割-最大流)
  7. 舞蹈链(DLX)模板
  8. HDU - 6186 CS Course(维护前缀+后缀)
  9. python高级语法-高阶函数之map的使用方法
  10. 【数据结构】C++单链表实现多项式加法(直接输入多项式)