一.什么是cas
CAS的全称是Compare-And-Swap,他是一条CPU并发原语。
java中的CAS,都是通过unsafe类实现的,其主要的操作是,当一个线程从主内存拿到一个变量到自己工作内存,并经过计算处理,准备写回主内存的时候,会首先比对当前主内存的变量指向的内存地址里面的值,与期望值(线程一开始拿变量时,变量对应的值)是否相等,如果相等,则表示没有其他线程对这个变量操作过,随后就将要更新的值写进主内存中。假如不相等,则表示有线程修改过这个变量,则会把主内存中变量的最新值拿回去,重新做一次计算操作,以此循环。
二.cas的底层原理
下面是java atomicInteger的代码:
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
下面是unsafe.class中的代码(这个类是java的原生类,在jdk的rt.jar/sun/misc里面):
//第一个参数var1为给定对象,var2为对象内存的偏移量,通过这个偏移量迅速定位字段并设置或获取该字段的值, //var5表示期望值,var4表示要添加的数值 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; }
一般来说,java无法直接访问底层系统,需要通过本地native方法来访问,而unsafe相当于一个后门,基于该类可以直接操作特定的内存。
可以看出,unsafe类可以直接操作指针,根据给定的对象和内存偏移量迅速地获取到变量值。在do...while中,首先根据对象和内存偏移量拿到一个值作为期望值,然后在while的条件语句中,再一次根据对象和内存偏移量获取变量的当前值,并与期望值作出对比,如果相等,则加上var4。假如不相等,则从新获得期望值,并循环。
三.CAS的缺点
最明显的一点,CAS有可能出现一个很长的循环,假如线程一直没有写成功,那他就会一直自旋,非常消耗CPU资源。而且它只能保证一个共享变量的操作,对于多变量操作,只能加锁。
其次就是ABA问题,导致ABA问题的原因是两个线程的工作时间差距太大。例如线程a需要10秒,线程b需要2秒,它们同时从主线程中拿到x1并开始工作,在10秒中,线程b先把x1改成x2,x2改成x3。。。。最后x3又该回去x1,这时候线程a算出结果x4并对主内存中的变量进行CAS操作,通过比较期望值和现时变量的值发现是一致的,就认为这段时间里面没有其他线程对变量进行修改过,但是实际上,这个变量以及是被修改过多次了。
原文:https://www.cnblogs.com/QicongLiang/p/13641067.html