1、循环时间长,开销大
cas方法底层有一个do....while....循环。
以Unsafe的getAndAddInt为例
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;
}
如果compareAndSwapInt()方法失败,就会一直尝试。如果CAS长时间一直不成功,可能会给CPU带来很大开销。
2、只能保证一个共享变量的原子操作
对于多个共享变量的原子操作,就不能用cas来保证其原子性,只能用加锁来保证。
3、ABA问题
CAS算法实现的一个重要前提需要提取内存中某时刻的数据并在当下时刻比较并交换,那么在这个时间差类会导致数据的变化。
在cas保证原子性的过程中,其实是有猫腻的。
线程A与线程B并发访问共享变量 int s = 0;
设想线程A的操作比较复杂,耗时很大,线程B则只比较后修改s,在一次线程A处理的时间内,线程B可以完成多次处理。
- 比如同一时间线程A与B在主物理内存中拷贝到自己的工作内存中的值都是0。
- 然后线程B将s 改为1,(这时主物理内存中的s还没有被A改变),然后线程B通过CAS比较并交换后,成功将内存中的s改为1。
- 注意:然后线程B在A修改之前又通过CAS将主内存中的s从1又改为0.
- 这时线程A在工作内存中将s改为999,Cas写入主内存中的时候发现s还是0(这个0是改过之后的0),与期望值一样,修改成功。
这样ABA问题可能不会给操作结果造成影响,但是可能会给具体的业务场景造成影响。(并不能代表这个过程是没问题的)