Java Concurrency traced the source of the two CAS

Java Concurrency traced the source of the two CAS

In the previous article, we know what is the CAS process and the implementation of CAS, in this article, we will follow step by step to see the source code underlying implementation of the principle of CAS.

Benpian is: The second "Kaige (Kaige Java kagejava) concurrent programming learning", "CAS series" tutorial series: traced from source to see the bottom of CAS is how to achieve.

The main contents are: CAS traced thoroughly to find the root of where the CAS.

A: View AtomicInteger.compareAndSet source

An article by the study, we know AtomicInteger.compareAndSet method does not lock ensures atomicity (The principle is unsafe + cas implemented), we take a look at its source code:

Thinking 1: variable Visibility

AtomicInteger objects (hereinafter referred Kaige: atoInteger) how to ensure the visibility of the variable memory of it?

View source code:

0fNpolejLXs


Reflections 2: Why i.compareAndSet 13 on a row (1, 1024) is false

We take a look at the atoInteger compareAndSet method. Kaige add a comment above.

0fNpom4CXM8


When you call this method unsafe compareAndSwapInt of what unsafe that? What is meant by this? ValueOffset What is it?

We then see atoInteger Source:

0fNpomWaHdg


We found Unsafe and valueOffset are obtained from one object to.

So what's this mean? In fact, this is the current atoInteger object.

So where Unsafe objects in it?

0fNpomvwi1I


0fNponFRYJc


0fNponZy1aK


We want to see the source code, how to see it? Found not see the source code ah. Do not worry, the source of this document can be found from openJdk the source code.

Then, we have to see OpenJdk8 source:

(PS: Download OpenJdk8 Source Kaige not go into here at last, given Kaige article.)

Downloaded, unzip after file location: openjdk \ jdk \ src \ share \ classes \ sun \ misc. As shown below:

0fNponzxFTc


We take a look Unsafe class above comment:

0fNpooMURF2


A collection of methods for performing low-level, unsafe operations.

什么意思呢?用于执行底层的(low-level,)、不安全操作的方法的集合。

就是说,这个类可以直接操作底层数据的。

需要说明的是:在这个对象中大量的方法使用了native来修饰(据网友统计高达82个)

0fNpoofVtBY


我们知道,Java的方法使用native关键字修饰的,说明这个方法不是Java自身的方法(非Java方法),可能调用的是其他语言的。如C或C++语言的方法。

我们再来看看:unsafe.objectFieldOffse()中的

0fNpop3RaqW


这个方法就是返回一个内存中访问偏移量。

return unsafe.compareAndSwapInt(this, valueOffset, expect, update);

0fNpopPFYUy


在unsafe类中compareAndSwapInt方法也是native的。我们在来看看这个方法调用操作系统底层C++的代码:

0fNpophJhuC


说明:

jint *addr:主内存中的变量值

old:对象工作区域的值

new_val:将要改变的值。

这三个是不是很熟悉,对。就是CAS的三个参数。

0fNpoqLV5km


分析第13行为什么返回false:

在11行的时候,设置主内存的变量值V=1.

在12行后,更新为V=2020了。

当执行到第13行的时候,

主内存:V=2020

程序工作区变量值jint *addr A的值:A=1

new_val:1024。

从调用C++代码我们可以分析到:

0fNpoqfyETI


在第5行的时候,因为1!=2020,所以return 的result就是false.

所以第13行输出的是false.

思考3:atoInteger.getAndIncrement()是怎么保证数据一致性的

0fNpor3Nrmq


调用的是getAndAddInt方法。接着查看unsafe的源码,就会发现CAS保证原子性的终极代码。

CAS保证原子性终极方法,如下图:

0fNporSKX56


看看:getObjectVolatile。方法发现是native.如下图:

0fNporx96Ya


再来看看compareAndSwapObject:

0fNpoubizSK


发现是native修饰的方法。说明不是Java的方法。这个我们等会再细说。

先来研究getAndSetObject:

0fNpoutyrgm


源码:

0fNpovdNjVo


我们来模拟:atoInteger.getAndIncrement();

假设默认值是0. 主内存的值是0

在调用getAndSetObject方法的几个参数说明:

Var1:当前atoInteger对象

Var2:当前偏移量(内存地址所在位置。如:三排四列)

Vart4:默认就是1

Var5:获取到的主内存的值

Var5+var4:将要更新的值。

从源码,我们看到是do while语句。为什么不是while语句呢?因为先要获取到主内存中变量最新的值,然后再判断。所以选用了do while语句。

我们来看看当CPU1线程1和CPU2线程B来执行的时候:

0fNpowHYSdU


两个线程都从主内存copay了i的值到自己工作内存空间后,进行+1的操作。

假设线程1再执行+1操作后,准备往主内存回写数据的时候,CPU1被挂起。然后CPU2竞争到资源之后,也操作i+1后,将更新后的值回写到了主内存中。然后切换到CPU1了,CPU1接着执行。对比代码分析:

0fNpowdHSwS


线程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.

And because there is! Non-symbol in front. So that while (! True), that is, while (false). Exit the loop, the return value of var5.

in conclusion:

By running the above analysis, we found atoInteger of getAndIncrement way to ensure atomicity is unsafe + CAS to ensure the atomicity of variable (which the statement is to do while later we will learn Spin)

wx.jpg


Guess you like

Origin blog.51cto.com/kaigejava/2481913