标签:生成 integer splay 变量 java语言 als name -keep cas
CAS是什么?
CAS全称Compare-And-Swap,它是一条CPU并发原语。它的作用是判断内存的某个位置的值是否为预期值,如果是则改为新值,在这个过程中是原子性的。
sum.misc.Unsafe类中有多个方法被native关键字标记,这说明该方法是原生态的方法,它是一个调用非java语言的接口,也就是说这个接口的实现是其他语言实现的。
CAS并发原语就是体现在java的sum.misc.Unsafe类中的各个方法,调用这个类中的CAS方法JVM就会通过其他语言生成若干条系统指令,完整这些指令的过程中,是不允许被中断的,所以CAS是一条CUP的原子指令,所以它不会造成数据不一致问题
多线程情况下,number变量每次++都会出现线程安全问题,AtomicInteger则不会,因为它保证了原子性
我们进去看,getAndIncrement调用的就是Unsafe类中的getAndAddInt方法,this表示当前对象,valueOffset表示变量值在内存中的偏移量(也就是内存地址)
我们再进入Unsafe类看看
var1就是getAndIncrement方法传过来的对象,var2是系统偏移量,这里是使用了do-while循环,一开始循环就通过var1对象和var2偏移量获取期望值var5,进入循环,compareAndSwapInt方法被native关键字标记的,所以他是原子性的 ,这里使用的是一个自旋锁,var2的值与var的值相等时,则使用新的值var5+var4,返回true,循环条件取反则结束循环,否则如果var2与var5不相等就继续循环,直到条件不满足再跳出循环
缺点:
-如果多次比较不成功,则会多次循环,时间开销大
-只能保证一个共享变量的原子操作
-ABA问题
什么是ABA问题?
ABA问题是CAS在取出内存中某个时刻的数据在比较并交换的这个时间差内导致数据的变化,最后的这个数据与开始取出内存中的数据一致依然能够比较成功。
ABA发生过程:T1线程读取内存值为A ----> T1线程被挂起,然后T2线程运行 ----> T2线程将内存值A改成B,然后又改回A ----> CUP调度到T1线程 ----> T1比较内存的值还是A,比较成功然后改成新的值
解决办法:每次线程更改内存中的某个值的时候加一个自增的数值,每改变一次自增1,当初始值与期望值相同时,再比较标志是否相同,相同时才能更改
代码:
100是内存中某个时刻的值,1是标志初始值,每次改变的时候自增1
标签:生成 integer splay 变量 java语言 als name -keep cas
原文地址:https://www.cnblogs.com/dgvt/p/12946123.html