Java并发编程之CAS二源码追根溯源
Java并发编程之CAS二源码追根溯源
在上一篇文章中,我们知道了什么是CAS以及CAS的执行流程,在本篇文章中,我们将跟着源码一步一步的查看CAS最底层实现原理。
本篇是《凯哥(凯哥Java:kagejava)并发编程学习》系列之《CAS系列》教程的第二篇:从源码追根溯源查看CAS最底层是怎么实现的。
本文主要内容:CAS追根溯源,彻底找到CAS的根在哪里。
一:查看AtomicInteger.compareAndSet源码
通过上一篇文章学习,我们知道了AtomicInteger.compareAndSet方法不加锁可以保证原子性(其原理就是unsafe+cas实现的),我们来看看其源码:
思考1:变量可见性
AtomicInteger对象(下文凯哥简称:atoInteger)怎么保证变量内存可见性呢?
查看源码:
思考2:为什么上一篇13行的i.compareAndSet(1,1024)是false
我们来看看atoInteger的compareAndSet方法。凯哥在上面添加了注释。
在调用unsafe的compareAndSwapInt这个方法的时候,unsafe是什么?this指的是什么?valueOffset又是什么呢?
我们接着查看atoInteger源码:
我们发现Unsafe以及valueOffset都是从一个对象中获取到的。
那么this指的是什么?其实this就是当前atoInteger对象。
那么Unsafe对象在哪里呢?
我们想要看源码,怎么查看呢?发现不能看源码啊。别急,这个文件的源码可以从openJdk的源码中查到。
接着,我们来查看OpenJdk8的源码:
(PS:下载OpenJdk8源码凯哥这里就不赘述了。在文章最后,凯哥给出)
下载完,解压之后,文件位置:openjdk\jdk\src\share\classes\sun\misc。如下图:
我们来看看Unsafe类上面的注解:
A collection of methods for performing low-level, unsafe operations.
什么意思呢?用于执行底层的(low-level,)、不安全操作的方法的集合。
就是说,这个类可以直接操作底层数据的。
需要说明的是:在这个对象中大量的方法使用了native来修饰(据网友统计高达82个)
我们知道,Java的方法使用native关键字修饰的,说明这个方法不是Java自身的方法(非Java方法),可能调用的是其他语言的。如C或C++语言的方法。
我们再来看看:unsafe.objectFieldOffse()中的
这个方法就是返回一个内存中访问偏移量。
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
在unsafe类中compareAndSwapInt方法也是native的。我们在来看看这个方法调用操作系统底层C++的代码:
说明:
jint *addr:主内存中的变量值
old:对象工作区域的值
new_val:将要改变的值。
这三个是不是很熟悉,对。就是CAS的三个参数。
分析第13行为什么返回false:
在11行的时候,设置主内存的变量值V=1.
在12行后,更新为V=2020了。
当执行到第13行的时候,
主内存:V=2020
程序工作区变量值jint *addr A的值:A=1
new_val:1024。
从调用C++代码我们可以分析到:
在第5行的时候,因为1!=2020,所以return 的result就是false.
所以第13行输出的是false.
思考3:atoInteger.getAndIncrement()是怎么保证数据一致性的
调用的是getAndAddInt方法。接着查看unsafe的源码,就会发现CAS保证原子性的终极代码。
CAS保证原子性终极方法,如下图:
看看:getObjectVolatile。方法发现是native.如下图:
再来看看compareAndSwapObject:
发现是native修饰的方法。说明不是Java的方法。这个我们等会再细说。
先来研究getAndSetObject:
源码:
我们来模拟:atoInteger.getAndIncrement();
假设默认值是0. 主内存的值是0
在调用getAndSetObject方法的几个参数说明:
Var1:当前atoInteger对象
Var2:当前偏移量(内存地址所在位置。如:三排四列)
Vart4:默认就是1
Var5:获取到的主内存的值
Var5+var4:将要更新的值。
从源码,我们看到是do while语句。为什么不是while语句呢?因为先要获取到主内存中变量最新的值,然后再判断。所以选用了do while语句。
我们来看看当CPU1线程1和CPU2线程B来执行的时候:
两个线程都从主内存copay了i的值到自己工作内存空间后,进行+1的操作。
假设线程1再执行+1操作后,准备往主内存回写数据的时候,CPU1被挂起。然后CPU2竞争到资源之后,也操作i+1后,将更新后的值回写到了主内存中。然后切换到CPU1了,CPU1接着执行。对比代码分析:
线程1在执行do后得到的值var5=1而不是0
然后while里面执行:var1和var2运算后的结果是0(工作区的值)。
因为0!=5 .所以this.comparAndSwapInt的值是false.
又因为前面有个! 非得符号。也就是!false。我们知道!false就是true.
也就是while(true)。While(true)后,接着循环执行。线程会放弃原有操作,重新从主内存中获取到最新数据(此时就是1了),然后再进行操作后。
又到了do,获取在主内存最新数据是1.接着走while()
因为,var1,var2获取到工作区的值是1 var5也等于1.1=1,成立了,执行var5+var5=1+1=2,来更新主内存的数据后返回true.
又因为前面有个!非的符号。所以就是while(!true),也就是while(false)。退出循环,返回var5的值。
结论:
通过上面的运行分析,我们发现atoInteger的getAndIncrement方法保证原子性是unsafe+CAS来保证变量原子性的(其中do while语句就是后面我们将要学到的自旋)
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Java并发编程之CAS第一篇-什么是CAS
Java并发编程之CAS第一篇-什么是CAS 通过前面几篇的学习,我们对并发编程两个高频知识点了解了其中的一个—volatitl。从这一篇文章开始,我们将要学习另一个知识点—CAS.本篇是《凯哥并发编程学习》系列之《CAS系列》教程的第一篇:什么是CAS。 本文主要内容: 生活中举例;CAS定义;CAS代码演示。 一:生活中的例子 在电影《智取威虎山》中,杨子荣进入威虎山的时候,土匪说:天王盖地虎,杨子荣对:宝塔镇河妖。类似这样的黑话,几个土匪和杨子荣对过之后,座山雕,三爷才发话:这么说,你是徐旅长的人了。相信电影中这段对黑话,大家都看过。有没有感觉很过瘾呢?那么问题来了,为什么几个人对过黑话之后,就能确定来者身份呢?因为在那个时候,占山为王,各个山头都有老大,但是又要和其他山头交流,不能用明话来说。于是大家就编了一些黑话。根据黑话不同,来确认对方的身份。 这个过程如果站在计算机多线程并发编程角度来理解的话,可以这么来理解。黑话库就是主内存中变量杨子荣和其他土F是不同的线程。,他们之间的黑话就是各自从主内存复制的变量副本。当T匪A(也就是线程A):天王盖地虎是自己的副本的数据,想要更新...
- 下一篇
03月26日云栖号头条:支付宝自研数据库OceanBase通过阿里云向全球开放
云栖号:https://yqh.aliyun.com第一手的上云资讯,不同行业精选的上云企业案例库,基于众多成功案例萃取而成的最佳实践,助力您上云决策! 今日最新云头条快讯: 支付宝自研的金融级分布式数据库OceanBase正式通过阿里云向全球开放,企业可在云上获得“支付宝同款”的数据库处理能力;近日,由格力电器全资持股的珠海格力智能装备有限公司新增多项专利信息,其中诸多专利与机器人相关。 一起来看最新的资讯: 支付宝自研数据库OceanBase通过阿里云向全球开放 支付宝自研的金融级分布式数据库OceanBase正式通过阿里云向全球开放,企业可在云上获得“支付宝同款”的数据库处理能力。介绍称,OceanBase数据库可实现数千亿条记录、数百TB数据上的跨行跨表事务,此外,OceanBase可兼容Oracle和Mysql数据库。 钟南山院士出席中欧抗疫视频会:发病早期病人具有更高的传染性 钟南山院士等中国专家参加中欧抗疫视频会,与来自德国、意大利、英国、罗马尼亚等国的专家一起交流了新冠肺炎全球疫情下各国疫情的状态与应对的策略,分享诊疗方案及医护人员防护经验。会议上,钟南山院士向各国专家...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Mario游戏-低调大师作品
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8编译安装MySQL8.0.19
- MySQL8.0.19开启GTID主从同步CentOS8